diff --git a/.gitignore b/.gitignore index 8cd3d476e..e49219859 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,5 @@ local.properties # Maven maven.properties /*/maven.properties + +hawkbit-repository/hawkbit-repository-jpa/.springBeans diff --git a/MIGRATION.md b/MIGRATION.md index 8db1ee57c..f9d9fff51 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -11,3 +11,10 @@ ### REST API model changes for clients - ENTITYPagedList classes have been removed; generic PagedList used instead (e.g. PagedList instead of TargetPagedList). - ENTITYsrest classes have been removed; List used instead (e.g. List instead of TargetsRest) + +### Renamed api annotations +- Annotation `org.eclipse.hawkbit.rest.resource.EnableRestResources` have changed to `org.eclipse.hawkbit.mgmt.annotation.EnableMgmtApi` +- Annotation `org.eclipse.hawkbit.ddi.resource.EnableDirectDeviceApi` have changed to `org.eclipse.hawkbit.ddi.annotation.EnableDdiApi` + +### Renamed maven modules +- Module hawkbit-mgmt-api-client have changed to hawkbit-example-mgmt-simulator \ No newline at end of file diff --git a/README.md b/README.md index e61e5e9d1..bc00c5c8d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ Build: [![Circle CI](https://circleci.com/gh/eclipse/hawkbit.svg?style=svg)](https://circleci.com/gh/eclipse/hawkbit) + + # Eclipse.IoT hawkBit - Update Server [hawkBit](https://projects.eclipse.org/projects/iot.hawkbit) is an domain independent back end solution for rolling out software updates to constrained edge devices as well as more powerful controllers and gateways connected to IP based networking infrastructure. @@ -41,9 +43,9 @@ $ java -jar ./examples/hawkbit-example-app/target/hawkbit-example-app-#version#. $ java -jar ./examples/hawkbit-device-simulator/target/hawkbit-device-simulator-#version#.jar ``` #### Generate Getting Started data -[Example Management API Client](examples/hawkbit-mgmt-api-client) +[Example Management API Client](examples/hawkbit-example-mgmt-simulator) ``` -$ java -jar ./examples/hawkbit-mgmt-api-client/target/hawkbit-mgmt-api-client-#version#.jar +$ java -jar ./examples/hawkbit-example-mgmt-simulator/target/hawkbit-example-mgmt-simulator-#version#.jar ``` # Releases and Roadmap @@ -57,16 +59,22 @@ $ java -jar ./examples/hawkbit-mgmt-api-client/target/hawkbit-mgmt-api-client-#v # Modules -`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 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. -`hawkbit-ui` : Vaadin UI. -`hawkbit-cache-redis` : spring cache manager configuration and implementation with redis, distributed cache and distributed events. +* `examples` : hawkBit examples +* `hawkbit-artifact-repository-mongo` : Artifact repository implementation to mongoDB. +* `hawkbit-autoconfigure` : Spring-boot auto-configuration. +* `hawkbit-cache-redis` : Spring cache manager configuration and implementation with redis, distributed cache and distributed events. +* `hawkbit-core` : Core elements for internal interfaces and utility classes. +* `hawkbit-ddi-api` : The hawkBit DDI API. +* `hawkbit-ddi-dl-api` : The hawkBit DDI Download API. +* `hawkbit-ddi-resource` : Implementation of the hawkBit DDI API +* `hawkbit-dmf-amqp` : AMQP endpoint implementation for the DMF API. +* `hawkbit-dmf-api` : API for the Device Management Integration. +* `hawkbit-http-security` : Implementation for security filters for HTTP. +* `hawkbit-mgmt-api` : The hawkBit Management API +* `hawkbit-mgmt-resource` : Implementation of the hawkBit Management API +* `hawkbit-repository` : Repository implementation based on SQL for all meta-data. +* `hawkbit-rest-core` : Core elements for the rest modules. +* `hawkbit-security-core` : Core security elements. +* `hawkbit-security-integration` : Security integration elements to integrate security into hawkBit. +* `hawkbit-test-report` : Test reports +* `hawkbit-ui` : Vaadin UI. \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index 0d6e0c18a..0aebbc117 100644 --- a/examples/README.md +++ b/examples/README.md @@ -2,8 +2,11 @@ Example projects that show how _hawkBit_ can be used to create, run or access an _hawkBit_ empowered update server. -- `hawkbit-device-simulator` : Simulates device software updates, leveraging the hawkBit device integration options. -- `hawkbit-example-app` : Allows you to run a Spring Boot and hawkBit based update server. Includes all _hawkBit_ interfaces, i.e. DDI, DMF, Mgmt-API, Mgmt-UI. - `hawkbit-custom-theme-example` : Example for a customized theme for Management UI. -- `hawkbit-mgmt-api-client` : Example client for the _hawkBit_ Management API. +- `hawkbit-device-simulator` : Simulates device software updates, leveraging the hawkBit device integration options. +- `hawkbit-example-app` : Allows you to run the Spring Boot hawkBit app. Includes all _hawkBit_ interfaces, i.e. DDI, DMF, Mgmt-API, Mgmt-UI. +- `hawkbit-example-core-feign-client` : Core resources for the client examples. +- `hawkbit-example-ddi-feign-client` : Example _hawkBit_ DDI client based on the _hawkBit_ DDI API. +- `hawkbit-example-mgmt-feign-client` : Example _hawkBit_ Management client based on the _hawkBit_ Management API +- `hawkbit-example-mgmt-simulator` : Example client simulation for the _hawkBit_ Management API based on Spring Boot and the hawkbit-example-mgmt-feign-client. diff --git a/examples/hawkbit-custom-theme-example/pom.xml b/examples/hawkbit-custom-theme-example/pom.xml index 7caa99ba2..875db18e3 100644 --- a/examples/hawkbit-custom-theme-example/pom.xml +++ b/examples/hawkbit-custom-theme-example/pom.xml @@ -79,6 +79,11 @@ hawkbit-http-security ${project.version} + + org.eclipse.hawkbit + hawkbit-repository-jpa + ${project.version} + 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 abf2740fa..7f80eb05b 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 @@ -8,11 +8,10 @@ package org.eclipse.hawkbit.app; * http://www.eclipse.org/legal/epl-v10.html */ -import org.eclipse.hawkbit.RepositoryApplicationConfiguration; +import org.eclipse.hawkbit.EnableJpaRepository; import org.eclipse.hawkbit.autoconfigure.security.EnableHawkbitManagedSecurityConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Import; /** * A {@link SpringBootApplication} annotated class with a main method to start. @@ -20,10 +19,10 @@ import org.springframework.context.annotation.Import; * */ @SpringBootApplication -@Import({ RepositoryApplicationConfiguration.class }) @EnableHawkbitManagedSecurityConfiguration // Exception squid:S1118 - Spring boot standard behavior @SuppressWarnings({ "squid:S1118" }) +@EnableJpaRepository public class Start { /** * Main method to start the spring-boot application. diff --git a/examples/hawkbit-device-simulator/pom.xml b/examples/hawkbit-device-simulator/pom.xml index 728fe0595..035bcebfc 100644 --- a/examples/hawkbit-device-simulator/pom.xml +++ b/examples/hawkbit-device-simulator/pom.xml @@ -19,7 +19,7 @@ hawkbit-device-simulator - hawkBit :: Device Simulator + hawkBit-example :: Device Simulator Device Management Federation API based simulator @@ -71,6 +71,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-logging + org.springframework.security spring-security-web @@ -82,16 +86,6 @@ org.springframework.boot spring-boot-starter - - - org.springframework.boot - spring-boot-starter-logging - - - - - org.springframework.boot - spring-boot-starter-log4j2 com.vaadin @@ -106,10 +100,6 @@ org.springframework.boot spring-boot-autoconfigure - - org.springframework.boot - spring-boot-autoconfigure - com.google.guava guava @@ -117,12 +107,10 @@ com.netflix.feign feign-jackson - 8.14.1 com.netflix.feign feign-core - 8.12.1 com.jayway.jsonpath 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 890f43367..a2a036e1b 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 @@ -27,7 +27,7 @@ public abstract class AbstractSimulatedDevice { private UpdateStatus updateStatus = new UpdateStatus(ResponseStatus.SUCCESSFUL, "Simulation complete!"); private Protocol protocol = Protocol.DMF_AMQP; private String targetSecurityToken; - + private int pollDelaySec; private int nextPollCounterSec; /** @@ -84,13 +84,30 @@ public abstract class AbstractSimulatedDevice { * the ID of the simulated device * @param tenant * the tenant of the simulated device + * @param int + * pollDelaySec */ - AbstractSimulatedDevice(final String id, final String tenant, final Protocol protocol) { + AbstractSimulatedDevice(final String id, final String tenant, final Protocol protocol, final int pollDelaySec) { this.id = id; this.tenant = tenant; this.status = Status.UNKNWON; this.progress = 0.0; this.protocol = protocol; + this.pollDelaySec = pollDelaySec; + } + + /** + * Can be called by a scheduler to trigger a device polling, like in real + * scenarios devices are frequently asking for updates etc. + */ + public abstract void poll(); + + public int getPollDelaySec() { + return pollDelaySec; + } + + public void setPollDelaySec(final int pollDelaySec) { + this.pollDelaySec = pollDelaySec; } /** 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 26e613dd9..677d77a37 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 @@ -23,7 +23,6 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice { private static final Logger LOGGER = LoggerFactory.getLogger(DDISimulatedDevice.class); - private final int pollDelaySec; private final ControllerResource controllerResource; private final DeviceSimulatorUpdater deviceUpdater; @@ -45,11 +44,9 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice { */ public DDISimulatedDevice(final String id, final String tenant, final int pollDelaySec, final ControllerResource controllerResource, final DeviceSimulatorUpdater deviceUpdater) { - super(id, tenant, Protocol.DDI_HTTP); - this.pollDelaySec = pollDelaySec; + super(id, tenant, Protocol.DDI_HTTP, pollDelaySec); this.controllerResource = controllerResource; this.deviceUpdater = deviceUpdater; - setNextPollCounterSec(pollDelaySec); } @Override @@ -58,13 +55,10 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice { removed = true; } - public int getPollDelaySec() { - return pollDelaySec; - } - /** * Polls the base URL for the DDI API interface. */ + @Override public void poll() { if (!removed) { final String basePollJson = controllerResource.get(getTenant(), getId()); 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 6b79a85b8..65227b55d 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 @@ -8,10 +8,13 @@ */ package org.eclipse.hawkbit.simulator; +import org.eclipse.hawkbit.simulator.amqp.SpSenderService; + /** * A simulated device using the DMF API of the hawkBit update server. */ public class DMFSimulatedDevice extends AbstractSimulatedDevice { + private final SpSenderService spSenderService; /** * @param id @@ -19,8 +22,15 @@ public class DMFSimulatedDevice extends AbstractSimulatedDevice { * @param tenant * the tenant of the simulated device */ - public DMFSimulatedDevice(final String id, final String tenant) { - super(id, tenant, Protocol.DMF_AMQP); + public DMFSimulatedDevice(final String id, final String tenant, final SpSenderService spSenderService, + final int pollDelaySec) { + super(id, tenant, Protocol.DMF_AMQP, pollDelaySec); + this.spSenderService = spSenderService; + } + + @Override + public void poll() { + spSenderService.createOrUpdateThing(super.getTenant(), super.getId()); } } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorRepository.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorRepository.java index 68db9df45..66ceacc8e 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorRepository.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorRepository.java @@ -9,8 +9,8 @@ package org.eclipse.hawkbit.simulator; import java.util.Collection; -import java.util.LinkedHashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -25,7 +25,7 @@ import org.springframework.stereotype.Service; @Service public class DeviceSimulatorRepository { - private final Map devices = new LinkedHashMap<>(); + private final Map devices = new ConcurrentHashMap<>(); @Autowired private SimulatedDeviceFactory deviceFactory; 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 e7b81b017..69ed4fd4a 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 @@ -10,8 +10,6 @@ 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; @@ -34,6 +32,7 @@ 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.Artifact.UrlProtocol; import org.eclipse.hawkbit.dmf.json.model.SoftwareModule; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus; @@ -59,7 +58,7 @@ import com.google.common.io.ByteStreams; public class DeviceSimulatorUpdater { private static final Logger LOGGER = LoggerFactory.getLogger(DeviceSimulatorUpdater.class); - private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(4); + private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(8); @Autowired private SpSenderService spSenderService; @@ -99,7 +98,8 @@ public class DeviceSimulatorUpdater { // plug and play - non existing device will be auto created if (device == null) { - device = repository.add(deviceFactory.createSimulatedDevice(id, tenant, Protocol.DMF_AMQP, -1, null, null)); + device = repository + .add(deviceFactory.createSimulatedDevice(id, tenant, Protocol.DMF_AMQP, 1800, null, null)); } device.setProgress(0.0); @@ -149,6 +149,8 @@ public class DeviceSimulatorUpdater { eventbus.post(new ProgressUpdate(device)); return; } + // download is 80% of the game after all + device.setProgress(0.8); } final double newProgress = device.getProgress() + 0.2; @@ -195,18 +197,14 @@ public class DeviceSimulatorUpdater { 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; - } - }); + + if (artifact.getUrls().containsKey(UrlProtocol.HTTPS)) { + status.add(downloadUrl(artifact.getUrls().get(UrlProtocol.HTTPS), targetToken, + artifact.getHashes().getSha1(), artifact.getSize())); + } else if (artifact.getUrls().containsKey(UrlProtocol.HTTP)) { + status.add(downloadUrl(artifact.getUrls().get(UrlProtocol.HTTP), targetToken, + artifact.getHashes().getSha1(), artifact.getSize())); + } } private static UpdateStatus downloadUrl(final String url, final String targetToken, final String sha1Hash, @@ -233,18 +231,15 @@ public class DeviceSimulatorUpdater { return new UpdateStatus(ResponseStatus.ERROR, message); } - final File tempFile = File.createTempFile("uploadFile", null); + // Exception squid:S2070 - not used for hashing sensitive + // data + @SuppressWarnings("squid:S2070") 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); + try (final BufferedOutputStream bdos = new BufferedOutputStream( + new DigestOutputStream(ByteStreams.nullOutputStream(), md))) { + try (BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent())) { + overallread = ByteStreams.copy(bis, bdos); } } @@ -262,7 +257,7 @@ public class DeviceSimulatorUpdater { } } catch (IOException | KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { - LOGGER.error("Failed to download {} with {}", url, e.getMessage()); + LOGGER.error("Failed to download" + url, e); return new UpdateStatus(ResponseStatus.ERROR, "Failed to download " + url + ": " + e.getMessage()); } @@ -272,6 +267,10 @@ public class DeviceSimulatorUpdater { } private static String hideTokenDetails(final String targetToken) { + if (targetToken == null) { + return ""; + } + if (targetToken.isEmpty()) { return ""; } 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 956d6d36a..96b4a1e97 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 @@ -8,12 +8,11 @@ */ package org.eclipse.hawkbit.simulator; -import java.util.List; +import java.util.Collection; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate; import org.slf4j.Logger; @@ -51,18 +50,17 @@ public class NextPollTimeController { private class NextPollUpdaterRunnable implements Runnable { @Override public void run() { - final List devices = repository.getAll().stream() - .filter(device -> device instanceof DDISimulatedDevice).collect(Collectors.toList()); + final Collection devices = repository.getAll(); devices.forEach(device -> { int nextCounter = device.getNextPollCounterSec() - 1; - if (nextCounter < 0 && device instanceof DDISimulatedDevice) { + if (nextCounter < 0) { try { - pollService.submit(() -> ((DDISimulatedDevice) device).poll()); + pollService.submit(() -> device.poll()); } catch (final IllegalStateException e) { LOGGER.trace("Device could not be polled", e); } - nextCounter = ((DDISimulatedDevice) device).getPollDelaySec(); + nextCounter = device.getPollDelaySec(); } device.setNextPollCounterSec(nextCounter); 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 f29aad001..8d5c5e0b1 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 @@ -11,6 +11,7 @@ package org.eclipse.hawkbit.simulator; import java.net.URL; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; +import org.eclipse.hawkbit.simulator.amqp.SpSenderService; import org.eclipse.hawkbit.simulator.http.ControllerResource; import org.eclipse.hawkbit.simulator.http.GatewayTokenInterceptor; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +29,9 @@ public class SimulatedDeviceFactory { @Autowired private DeviceSimulatorUpdater deviceUpdater; + @Autowired + private SpSenderService spSenderService; + /** * Creating a simulated devices. * @@ -41,7 +45,7 @@ public class SimulatedDeviceFactory { */ public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant, final Protocol protocol) { - return createSimulatedDevice(id, tenant, protocol, 30, null, null); + return createSimulatedDevice(id, tenant, protocol, 1800, null, null); } /** @@ -55,7 +59,7 @@ public class SimulatedDeviceFactory { * the protocol which should be used be the simulated device * @param pollDelaySec * the poll delay time in seconds which should be used for - * {@link DDISimulatedDevice}s + * {@link DDISimulatedDevice}s and {@link DMFSimulatedDevice} * @param baseEndpoint * the http base endpoint which should be used for * {@link DDISimulatedDevice}s @@ -68,7 +72,7 @@ public class SimulatedDeviceFactory { final int pollDelaySec, final URL baseEndpoint, final String gatewayToken) { switch (protocol) { case DMF_AMQP: - return new DMFSimulatedDevice(id, tenant); + return new DMFSimulatedDevice(id, tenant, spSenderService, pollDelaySec); case DDI_HTTP: final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger()) .requestInterceptor(new GatewayTokenInterceptor(gatewayToken)).logLevel(Logger.Level.BASIC) diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java index 649d88477..43f954c00 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java @@ -66,7 +66,7 @@ public class SimulationController { @RequestParam(value = "tenant", defaultValue = "DEFAULT") final String tenant, @RequestParam(value = "api", defaultValue = "dmf") final String api, @RequestParam(value = "endpoint", defaultValue = "http://localhost:8080") final String endpoint, - @RequestParam(value = "polldelay", defaultValue = "30") final int pollDelay, + @RequestParam(value = "polldelay", defaultValue = "1800") final int pollDelay, @RequestParam(value = "gatewaytoken", defaultValue = "") final String gatewayToken) throws MalformedURLException { @@ -86,10 +86,6 @@ public class SimulationController { final String deviceId = name + i; repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, protocol, pollDelay, new URL(endpoint), gatewayToken)); - - if (protocol == Protocol.DMF_AMQP) { - spSenderService.createOrUpdateThing(tenant, deviceId); - } } return ResponseEntity.ok("Updated " + amount + " DMF connected targets!"); diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationProperties.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationProperties.java index 354263934..fb98ff67e 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationProperties.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationProperties.java @@ -10,6 +10,7 @@ package org.eclipse.hawkbit.simulator; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; import org.hibernate.validator.constraints.NotEmpty; @@ -68,9 +69,9 @@ public class SimulationProperties { private String endpoint = "http://localhost:8080"; /** - * Poll time in case of DDI API based simulation. + * Poll time in {@link TimeUnit#SECONDS} for simulated devices. */ - private int pollDelay = 30; + private int pollDelay = (int) TimeUnit.MINUTES.toSeconds(30); /** * Optional gateway token for DDI API based simulation. diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatorStartup.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatorStartup.java index 19367a9d4..486eb4b5e 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatorStartup.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatorStartup.java @@ -11,7 +11,6 @@ package org.eclipse.hawkbit.simulator; import java.net.MalformedURLException; import java.net.URL; -import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; import org.eclipse.hawkbit.simulator.amqp.SpSenderService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,10 +53,6 @@ public class SimulatorStartup implements ApplicationListener { + if (ack) { + LOGGER.debug("Message with correlation ID {} confirmed by broker.", correlationData.getId()); + } else { + LOGGER.error("Broker is unable to handle message with correlation ID {} : {}", correlationData.getId(), + cause); + } + + }); + + return rabbitTemplate; + } + + @Configuration + protected static class RabbitConnectionFactoryCreator { + + /** + * {@link ConnectionFactory} with enabled publisher confirms and + * heartbeat. + * + * @param config + * with standard {@link RabbitProperties} + * @return {@link ConnectionFactory} + */ + @Bean + public ConnectionFactory rabbitConnectionFactory(final RabbitProperties config) { + final CachingConnectionFactory factory = new CachingConnectionFactory(); + factory.setRequestedHeartBeat(60); + factory.setPublisherConfirms(true); + + final String addresses = config.getAddresses(); + factory.setAddresses(addresses); + if (config.getHost() != null) { + factory.setHost(config.getHost()); + factory.setPort(config.getPort()); + } + if (config.getUsername() != null) { + factory.setUsername(config.getUsername()); + } + if (config.getPassword() != null) { + factory.setPassword(config.getPassword()); + } + if (config.getVirtualHost() != null) { + factory.setVirtualHost(config.getVirtualHost()); + } + return factory; + } } /** @@ -65,9 +118,12 @@ public class AmqpConfiguration { * @return the queue */ @Bean - public Queue receiverConnectorQueueFromSp() { - return new Queue(amqpProperties.getReceiverConnectorQueueFromSp(), true, false, false, - getDeadLetterExchangeArgs()); + public Queue receiverConnectorQueueFromHawkBit() { + final Map arguments = getDeadLetterExchangeArgs(); + arguments.putAll(getTTLMaxArgs()); + + return QueueBuilder.nonDurable(amqpProperties.getReceiverConnectorQueueFromSp()).autoDelete() + .withArguments(arguments).build(); } /** @@ -77,19 +133,19 @@ public class AmqpConfiguration { */ @Bean public FanoutExchange exchangeQueueToConnector() { - return new FanoutExchange(amqpProperties.getSenderForSpExchange()); + return new FanoutExchange(amqpProperties.getSenderForSpExchange(), false, true); } /** * Create the Binding - * {@link AmqpConfiguration#receiverConnectorQueueFromSp()} to + * {@link AmqpConfiguration#receiverConnectorQueueFromHawkBit()} to * {@link AmqpConfiguration#exchangeQueueToConnector()}. * * @return the binding and create the queue and exchange */ @Bean public Binding bindReceiverQueueToSpExchange() { - return BindingBuilder.bind(receiverConnectorQueueFromSp()).to(exchangeQueueToConnector()); + return BindingBuilder.bind(receiverConnectorQueueFromHawkBit()).to(exchangeQueueToConnector()); } /** @@ -99,7 +155,7 @@ public class AmqpConfiguration { */ @Bean public Queue deadLetterQueue() { - return new Queue(amqpProperties.getDeadLetterQueue(), true, false, true); + return QueueBuilder.nonDurable(amqpProperties.getDeadLetterQueue()).withArguments(getTTLMaxArgs()).build(); } /** @@ -109,7 +165,7 @@ public class AmqpConfiguration { */ @Bean public FanoutExchange exchangeDeadLetter() { - return new FanoutExchange(amqpProperties.getDeadLetterExchange()); + return new FanoutExchange(amqpProperties.getDeadLetterExchange(), false, true); } /** @@ -131,10 +187,10 @@ public class AmqpConfiguration { @Bean(name = { "listenerContainerFactory" }) public SimpleRabbitListenerContainerFactory listenerContainerFactory() { final SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory(); - containerFactory.setDefaultRequeueRejected(false); + containerFactory.setDefaultRequeueRejected(true); containerFactory.setConnectionFactory(connectionFactory); - containerFactory.setConcurrentConsumers(20); - containerFactory.setMaxConcurrentConsumers(20); + containerFactory.setConcurrentConsumers(3); + containerFactory.setMaxConcurrentConsumers(10); containerFactory.setPrefetchCount(20); return containerFactory; } @@ -145,4 +201,11 @@ public class AmqpConfiguration { return args; } + private static Map getTTLMaxArgs() { + final Map args = new HashMap<>(); + args.put("x-message-ttl", Duration.ofDays(1).toMillis()); + args.put("x-max-length", 100_000); + return args; + } + } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java index bd48bbe12..8bb1e1292 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java @@ -82,21 +82,4 @@ public class MessageService { clazz.getTypeName()); return (T) rabbitTemplate.getMessageConverter().fromMessage(message); } - - /** - * Method to verify if lwm2m header is set. - * - * @param message - * the message with the header - * @param header - * the header to verify - */ - public void checkIfLwm2mHeaderEmpty(final Message message, final String header) { - final Object headerObject = message.getMessageProperties().getHeaders().get(header); - if (null == headerObject) { - logAndThrowMessageError(message, "Header of " + header + "empty."); - } - - } - } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/ReceiverService.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/ReceiverService.java index f5c02789e..2e8833bab 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/ReceiverService.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/ReceiverService.java @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.simulator.amqp; +import org.springframework.amqp.AmqpRejectAndDontRequeueException; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.rabbit.core.RabbitTemplate; @@ -55,7 +56,7 @@ public abstract class ReceiverService extends MessageService { if (contentType != null && contentType.contains("json")) { return; } - throw new IllegalArgumentException("Content-Type is not JSON compatible"); + throw new AmqpRejectAndDontRequeueException("Content-Type is not JSON compatible"); } } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SenderService.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SenderService.java index 6ed6ff0cb..f2c0e7fcb 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SenderService.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SenderService.java @@ -8,9 +8,14 @@ */ package org.eclipse.hawkbit.simulator.amqp; +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.support.CorrelationData; import org.springframework.amqp.support.converter.AbstractJavaTypeMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -22,6 +27,8 @@ import org.springframework.beans.factory.annotation.Autowired; */ public abstract class SenderService extends MessageService { + private static final Logger LOGGER = LoggerFactory.getLogger(SenderService.class); + /** * Constructor for sender service. * @@ -40,18 +47,26 @@ public abstract class SenderService extends MessageService { /** * Send a message if the message is not null. * - * @param adress + * @param address * the exchange name * @param message * the amqp message which will be send if its not null */ - public void sendMessage(final String adress, final Message message) { + public void sendMessage(final String address, final Message message) { if (message == null) { return; } message.getMessageProperties().getHeaders().remove(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME); - rabbitTemplate.setExchange(adress); - rabbitTemplate.send(message); + final String correlationId = UUID.randomUUID().toString(); + message.getMessageProperties().setCorrelationId(correlationId.getBytes()); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Sending message {} to exchange {} with correlationId {}", message, address, correlationId); + } else { + LOGGER.debug("Sending message to exchange {} with correlationId {}", address, correlationId); + } + + rabbitTemplate.send(address, null, message, new CorrelationData(correlationId)); } /** 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 e06b2baf3..4f2981be1 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 @@ -35,14 +35,21 @@ import com.google.common.collect.Lists; public class SpReceiverService extends ReceiverService { private static final Logger LOGGER = LoggerFactory.getLogger(ReceiverService.class); - public static final String SOFTWARE_MODULE_FIRMWARE = "firmware"; - private final SpSenderService spSenderService; private final DeviceSimulatorUpdater deviceUpdater; /** * Constructor. + * + * @param rabbitTemplate + * for sending messages + * @param amqpProperties + * for amqp configuration + * @param spSenderService + * to send messages + * @param deviceUpdater + * simulator service for updates */ @Autowired public SpReceiverService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties, diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/NextPollCounterUpdate.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/NextPollCounterUpdate.java index b9d7b9027..5e98ebb64 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/NextPollCounterUpdate.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/NextPollCounterUpdate.java @@ -8,7 +8,7 @@ */ package org.eclipse.hawkbit.simulator.event; -import java.util.List; +import java.util.Collection; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice; @@ -20,7 +20,7 @@ import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice; */ public class NextPollCounterUpdate { - private final List devices; + private final Collection devices; /** * Creates poll timer update event. @@ -28,14 +28,14 @@ public class NextPollCounterUpdate { * @param devices * the devices which progress has been updated */ - public NextPollCounterUpdate(final List devices) { + public NextPollCounterUpdate(final Collection devices) { this.devices = devices; } /** * @return the devices of the event */ - public List getDevices() { + public Collection getDevices() { return devices; } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/GenerateDialog.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/GenerateDialog.java index e337e86e7..272531407 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/GenerateDialog.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/GenerateDialog.java @@ -76,7 +76,6 @@ public class GenerateDialog extends Window { pollDelayTextField = createRequiredTextfield("poll delay (sec)", new ObjectProperty(10), FontAwesome.CLOCK_O, new RangeValidator("Must be between 1 and 60", Integer.class, 1, 60)); - pollDelayTextField.setVisible(false); pollUrlTextField = createRequiredTextfield("base poll URL endpoint", "http://localhost:8080", FontAwesome.FLAG_O, new RegexpValidator( @@ -193,7 +192,6 @@ public class GenerateDialog extends Window { protocolGroup.select(Protocol.DMF_AMQP); protocolGroup.addValueChangeListener(event -> { final boolean directDeviceOptionSelected = event.getProperty().getValue().equals(Protocol.DDI_HTTP); - pollDelayTextField.setVisible(directDeviceOptionSelected); pollUrlTextField.setVisible(directDeviceOptionSelected); gatewayTokenTextField.setVisible(directDeviceOptionSelected); }); 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 4834bece9..9405edd2b 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,7 +8,7 @@ */ package org.eclipse.hawkbit.simulator.ui; -import java.util.List; +import java.util.Collection; import java.util.Locale; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice; @@ -167,7 +167,7 @@ public class SimulatorView extends VerticalLayout implements View { @SuppressWarnings("unchecked") @Subscribe public void pollCounterUpdate(final NextPollCounterUpdate update) { - final List devices = update.getDevices(); + final Collection devices = update.getDevices(); this.getUI().access(() -> devices.forEach(device -> { final BeanItem item = beanContainer.getItem(device.getId()); if (item != null) { diff --git a/examples/hawkbit-device-simulator/src/main/resources/application.properties b/examples/hawkbit-device-simulator/src/main/resources/application.properties index fbe7261be..5d3f04be7 100644 --- a/examples/hawkbit-device-simulator/src/main/resources/application.properties +++ b/examples/hawkbit-device-simulator/src/main/resources/application.properties @@ -24,7 +24,6 @@ spring.rabbitmq.virtualHost=/ spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.rabbitmq.dynamic=true -spring.rabbitmq.listener.prefetch=100 security.basic.enabled=false server.port=8083 diff --git a/examples/hawkbit-device-simulator/src/main/resources/logback.xml b/examples/hawkbit-device-simulator/src/main/resources/logback.xml new file mode 100644 index 000000000..5f3f1dbef --- /dev/null +++ b/examples/hawkbit-device-simulator/src/main/resources/logback.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/hawkbit-example-app/pom.xml b/examples/hawkbit-example-app/pom.xml index a5c0f864d..f501d5529 100644 --- a/examples/hawkbit-example-app/pom.xml +++ b/examples/hawkbit-example-app/pom.xml @@ -17,7 +17,7 @@ 0.2.0-SNAPSHOT hawkbit-example-app - hawkBit :: Example App + hawkBit-example :: UI Application @@ -64,7 +64,12 @@ org.eclipse.hawkbit - hawkbit-rest-resource + hawkbit-mgmt-resource + ${project.version} + + + org.eclipse.hawkbit + hawkbit-ddi-resource ${project.version} @@ -87,6 +92,11 @@ hawkbit-http-security ${project.version} + + org.eclipse.hawkbit + hawkbit-repository-jpa + ${project.version} + @@ -96,16 +106,26 @@ org.springframework.boot spring-boot-starter - - - org.springframework.boot - spring-boot-starter-logging - - + - org.springframework.boot - spring-boot-starter-log4j2 + org.apache.logging.log4j + log4j-api + + + + org.slf4j + jul-to-slf4j + + + + org.slf4j + jcl-over-slf4j + + + + org.slf4j + log4j-over-slf4j org.springframework.security 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 b08ae50d8..95fb39147 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 @@ -8,13 +8,12 @@ */ package org.eclipse.hawkbit.app; -import org.eclipse.hawkbit.RepositoryApplicationConfiguration; +import org.eclipse.hawkbit.EnableJpaRepository; import org.eclipse.hawkbit.autoconfigure.security.EnableHawkbitManagedSecurityConfiguration; -import org.eclipse.hawkbit.controller.EnableDirectDeviceApi; -import org.eclipse.hawkbit.rest.resource.EnableRestResources; +import org.eclipse.hawkbit.ddi.EnableDdiApi; +import org.eclipse.hawkbit.mgmt.EnableMgmtApi; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Import; /** * A {@link SpringBootApplication} annotated class with a main method to start. @@ -22,10 +21,10 @@ import org.springframework.context.annotation.Import; * */ @SpringBootApplication -@Import({ RepositoryApplicationConfiguration.class }) @EnableHawkbitManagedSecurityConfiguration -@EnableRestResources -@EnableDirectDeviceApi +@EnableMgmtApi +@EnableDdiApi +@EnableJpaRepository // Exception squid:S1118 - Spring boot standard behavior @SuppressWarnings({ "squid:S1118" }) public class Start { diff --git a/examples/hawkbit-example-app/src/main/resources/logback.xml b/examples/hawkbit-example-app/src/main/resources/logback.xml new file mode 100644 index 000000000..a76e39683 --- /dev/null +++ b/examples/hawkbit-example-app/src/main/resources/logback.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/hawkbit-example-core-feign-client/README.md b/examples/hawkbit-example-core-feign-client/README.md new file mode 100644 index 000000000..432a31c41 --- /dev/null +++ b/examples/hawkbit-example-core-feign-client/README.md @@ -0,0 +1,13 @@ +# Eclipse.IoT hawkBit - Example Core Feign Client + +This modules contains core beans that are needed to create a [Feign Client](https://github.com/Netflix/feign) with hwakBit. + +# Compile + +#### Build hawkbit-example-core-feign-client + +``` +$ cd hawkbit/examples/hawkbit-example-core-feign-client +$ mvn clean install +``` + diff --git a/examples/hawkbit-example-core-feign-client/pom.xml b/examples/hawkbit-example-core-feign-client/pom.xml new file mode 100644 index 000000000..5b3df2ef2 --- /dev/null +++ b/examples/hawkbit-example-core-feign-client/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + org.eclipse.hawkbit + hawkbit-examples-parent + 0.2.0-SNAPSHOT + + + hawkbit-example-core-feign-client + hawkBit-example :: Feign Core Client + + + + com.netflix.feign + feign-core + + + org.springframework + spring-web + + + org.springframework.cloud + spring-cloud-netflix-core + 1.0.7.RELEASE + + + org.slf4j + slf4j-api + + + com.netflix.feign + feign-slf4j + + + diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ApplicationJsonRequestHeaderInterceptor.java b/examples/hawkbit-example-core-feign-client/src/main/java/org/eclipse/hawkbit/feign/core/client/ApplicationJsonRequestHeaderInterceptor.java similarity index 95% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ApplicationJsonRequestHeaderInterceptor.java rename to examples/hawkbit-example-core-feign-client/src/main/java/org/eclipse/hawkbit/feign/core/client/ApplicationJsonRequestHeaderInterceptor.java index 75f3b0dd1..e7faca3b7 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ApplicationJsonRequestHeaderInterceptor.java +++ b/examples/hawkbit-example-core-feign-client/src/main/java/org/eclipse/hawkbit/feign/core/client/ApplicationJsonRequestHeaderInterceptor.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.mgmt.client; +package org.eclipse.hawkbit.feign.core.client; import org.springframework.http.MediaType; diff --git a/examples/hawkbit-example-core-feign-client/src/main/java/org/eclipse/hawkbit/feign/core/client/FeignClientConfiguration.java b/examples/hawkbit-example-core-feign-client/src/main/java/org/eclipse/hawkbit/feign/core/client/FeignClientConfiguration.java new file mode 100644 index 000000000..1512b7f9e --- /dev/null +++ b/examples/hawkbit-example-core-feign-client/src/main/java/org/eclipse/hawkbit/feign/core/client/FeignClientConfiguration.java @@ -0,0 +1,38 @@ +/** + * 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.feign.core.client; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.cloud.netflix.feign.FeignClientsConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +import feign.Contract; +import feign.Feign; + +/** + * Spring annotated java configuration class which defines necessary beans for + * configure the feign-client. + */ +@Configuration +@ConditionalOnClass(Feign.class) +@Import(FeignClientsConfiguration.class) +public class FeignClientConfiguration { + + @Bean + public ApplicationJsonRequestHeaderInterceptor jsonHeaderInterceptor() { + return new ApplicationJsonRequestHeaderInterceptor(); + } + + @Bean + public Contract feignContract() { + return new IgnoreMultipleConsumersProducersSpringMvcContract(); + } +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/IgnoreMultipleConsumersProducersSpringMvcContract.java b/examples/hawkbit-example-core-feign-client/src/main/java/org/eclipse/hawkbit/feign/core/client/IgnoreMultipleConsumersProducersSpringMvcContract.java similarity index 97% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/IgnoreMultipleConsumersProducersSpringMvcContract.java rename to examples/hawkbit-example-core-feign-client/src/main/java/org/eclipse/hawkbit/feign/core/client/IgnoreMultipleConsumersProducersSpringMvcContract.java index c796aa019..b04143cdf 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/IgnoreMultipleConsumersProducersSpringMvcContract.java +++ b/examples/hawkbit-example-core-feign-client/src/main/java/org/eclipse/hawkbit/feign/core/client/IgnoreMultipleConsumersProducersSpringMvcContract.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.mgmt.client; +package org.eclipse.hawkbit.feign.core.client; import java.lang.annotation.Annotation; import java.lang.reflect.Method; diff --git a/examples/hawkbit-example-ddi-feign-client/README.md b/examples/hawkbit-example-ddi-feign-client/README.md new file mode 100644 index 000000000..0eae90c23 --- /dev/null +++ b/examples/hawkbit-example-ddi-feign-client/README.md @@ -0,0 +1,14 @@ +# Eclipse.IoT hawkBit - Example DDI Feign Client API + +This modules contains the declarative client binding resources of the DDI API. +For more information see 'Feign Inheritance Support' at [Spring Cloud] (http://projects.spring.io/spring-cloud/spring-cloud.html). +Powered by [Feign](https://github.com/Netflix/feign). + +# Compile + +#### Build hawkbit-example-ddi-feign-client + +``` +$ cd hawkbit/examples/hawkbit-example-ddi-feign-client +$ mvn clean install +``` diff --git a/examples/hawkbit-example-ddi-feign-client/pom.xml b/examples/hawkbit-example-ddi-feign-client/pom.xml new file mode 100644 index 000000000..5388544db --- /dev/null +++ b/examples/hawkbit-example-ddi-feign-client/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + org.eclipse.hawkbit + hawkbit-examples-parent + 0.2.0-SNAPSHOT + + hawkbit-example-ddi-feign-client + + hawkBit-example :: DDI Feign Client + + + + + org.springframework.cloud + spring-cloud-netflix + 1.0.7.RELEASE + pom + import + + + + + + + org.eclipse.hawkbit + hawkbit-example-core-feign-client + ${project.version} + + + org.eclipse.hawkbit + hawkbit-ddi-dl-api + ${project.version} + + + org.eclipse.hawkbit + hawkbit-ddi-api + ${project.version} + + + com.google.guava + guava + + + com.netflix.feign + feign-core + + + com.netflix.feign + feign-jackson + + + com.fasterxml.jackson.core + jackson-databind + + + diff --git a/examples/hawkbit-example-ddi-feign-client/src/main/java/org/eclipse/hawkbit/ddi/client/resource/DdiDlArtifactStoreControllerResourceClient.java b/examples/hawkbit-example-ddi-feign-client/src/main/java/org/eclipse/hawkbit/ddi/client/resource/DdiDlArtifactStoreControllerResourceClient.java new file mode 100644 index 000000000..c37602d7a --- /dev/null +++ b/examples/hawkbit-example-ddi-feign-client/src/main/java/org/eclipse/hawkbit/ddi/client/resource/DdiDlArtifactStoreControllerResourceClient.java @@ -0,0 +1,21 @@ +/** + * 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.ddi.client.resource; + +import org.eclipse.hawkbit.ddi.dl.rest.api.DdiDlArtifactStoreControllerRestApi; +import org.eclipse.hawkbit.ddi.dl.rest.api.DdiDlRestConstants; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the artifact store controller resource of the DDI-DL API. + */ +@FeignClient(url = "${hawkbit.url:localhost:8080}/" + DdiDlRestConstants.ARTIFACTS_V1_REQUEST_MAPPING) +public interface DdiDlArtifactStoreControllerResourceClient extends DdiDlArtifactStoreControllerRestApi { + +} diff --git a/examples/hawkbit-example-ddi-feign-client/src/main/java/org/eclipse/hawkbit/ddi/client/resource/RootControllerResourceClient.java b/examples/hawkbit-example-ddi-feign-client/src/main/java/org/eclipse/hawkbit/ddi/client/resource/RootControllerResourceClient.java new file mode 100644 index 000000000..389f65da7 --- /dev/null +++ b/examples/hawkbit-example-ddi-feign-client/src/main/java/org/eclipse/hawkbit/ddi/client/resource/RootControllerResourceClient.java @@ -0,0 +1,21 @@ +/** + * 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.ddi.client.resource; + +import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants; +import org.eclipse.hawkbit.ddi.rest.api.DdiRootControllerRestApi; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the Rootcontroller resource of the DDI API. + */ +@FeignClient(url = "${hawkbit.url:localhost:8080}/" + DdiRestConstants.BASE_V1_REQUEST_MAPPING) +public interface RootControllerResourceClient extends DdiRootControllerRestApi { + +} diff --git a/examples/hawkbit-mgmt-api-client/.gitignore b/examples/hawkbit-example-mgmt-feign-client/.gitignore similarity index 100% rename from examples/hawkbit-mgmt-api-client/.gitignore rename to examples/hawkbit-example-mgmt-feign-client/.gitignore diff --git a/examples/hawkbit-example-mgmt-feign-client/README.md b/examples/hawkbit-example-mgmt-feign-client/README.md new file mode 100644 index 000000000..b5b7eb3d2 --- /dev/null +++ b/examples/hawkbit-example-mgmt-feign-client/README.md @@ -0,0 +1,15 @@ +# Eclipse.IoT hawkBit - Example Management Feign Client API + +This modules contains the declarative client binding resources of the Management API. +For more information see 'Feign Inheritance Support' at [Spring Cloud] (http://projects.spring.io/spring-cloud/spring-cloud.html). +Powered by [Feign](https://github.com/Netflix/feign). + +# Compile + +#### Build hawkbit-example-mgmt-feign-client + +``` +$ cd hawkbit/examples/hawkbit-example-mgmt-feign-client +$ mvn clean install +``` + diff --git a/examples/hawkbit-example-mgmt-feign-client/pom.xml b/examples/hawkbit-example-mgmt-feign-client/pom.xml new file mode 100644 index 000000000..7e96e3b00 --- /dev/null +++ b/examples/hawkbit-example-mgmt-feign-client/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + org.eclipse.hawkbit + hawkbit-examples-parent + 0.2.0-SNAPSHOT + + jar + hawkbit-example-mgmt-feign-client + hawkBit-example :: Management client API + + + + org.eclipse.hawkbit + hawkbit-example-core-feign-client + ${project.version} + + + org.eclipse.hawkbit + hawkbit-mgmt-api + ${project.version} + + + com.google.guava + guava + + + com.netflix.feign + feign-core + + + + com.netflix.feign + feign-jackson + + + com.fasterxml.jackson.core + jackson-databind + + + hibernate-validator + org.hibernate + + + \ No newline at end of file diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetResourceClient.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDistributionSetClientResource.java similarity index 62% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetResourceClient.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDistributionSetClientResource.java index 5ac11e012..40eb13b55 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetResourceClient.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDistributionSetClientResource.java @@ -8,13 +8,14 @@ */ package org.eclipse.hawkbit.mgmt.client.resource; -import org.eclipse.hawkbit.rest.resource.api.DistributionSetRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.springframework.cloud.netflix.feign.FeignClient; /** * Client binding for the DistributionSet resource of the management API. */ -@FeignClient(url = "${hawkbit.url:localhost:8080}/rest/v1/distributionsets") -public interface DistributionSetResourceClient extends DistributionSetRestApi { +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING) +public interface MgmtDistributionSetClientResource extends MgmtDistributionSetRestApi { } diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTagResourceClient.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDistributionSetTagClientResource.java similarity index 61% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTagResourceClient.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDistributionSetTagClientResource.java index 5fbdaf857..1070bbd9c 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTagResourceClient.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDistributionSetTagClientResource.java @@ -8,13 +8,13 @@ */ package org.eclipse.hawkbit.mgmt.client.resource; -import org.eclipse.hawkbit.rest.resource.api.DistributionSetTagRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTagRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.springframework.cloud.netflix.feign.FeignClient; /** * Client binding for the DistributionSetTag resource of the management API. */ -@FeignClient(url = "${hawkbit.url:localhost:8080}/rest/v1/distributionsettags") -public interface DistributionSetTagResourceClient extends DistributionSetTagRestApi { - +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING) +public interface MgmtDistributionSetTagClientResource extends MgmtDistributionSetTagRestApi { } diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTypeResourceClient.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDistributionSetTypeClientResource.java similarity index 61% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTypeResourceClient.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDistributionSetTypeClientResource.java index 300f8ddcb..451c53942 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTypeResourceClient.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDistributionSetTypeClientResource.java @@ -8,14 +8,15 @@ */ package org.eclipse.hawkbit.mgmt.client.resource; -import org.eclipse.hawkbit.rest.resource.api.DistributionSetTypeRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.springframework.cloud.netflix.feign.FeignClient; /** * Client binding for the DistributionSetType resource of the management API. * */ -@FeignClient(url = "${hawkbit.url:localhost:8080}/rest/v1/distributionsettypes") -public interface DistributionSetTypeResourceClient extends DistributionSetTypeRestApi { +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING) +public interface MgmtDistributionSetTypeClientResource extends MgmtDistributionSetTypeRestApi { } diff --git a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDownloadArtifactClientResource.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDownloadArtifactClientResource.java new file mode 100644 index 000000000..5c93edce5 --- /dev/null +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDownloadArtifactClientResource.java @@ -0,0 +1,22 @@ +/** + * 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.mgmt.client.resource; + +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadArtifactRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * A feign-client interface declaration which allows to build a feign-client + * stub. + */ +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) +public interface MgmtDownloadArtifactClientResource extends MgmtDownloadArtifactRestApi { + +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleResourceClient.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDownloadClientResource.java similarity index 59% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleResourceClient.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDownloadClientResource.java index 8610643ef..330d3908f 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleResourceClient.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtDownloadClientResource.java @@ -8,13 +8,13 @@ */ package org.eclipse.hawkbit.mgmt.client.resource; -import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleRestAPI; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.springframework.cloud.netflix.feign.FeignClient; /** - * Client binding for the SoftwareModule resource of the management API. + * */ -@FeignClient(url = "${hawkbit.url:localhost:8080}/rest/v1/softwaremodules") -public interface SoftwareModuleResourceClient extends SoftwareModuleRestAPI { - +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE) +public interface MgmtDownloadClientResource extends MgmtDownloadRestApi { } diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/RolloutResourceClient.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtRolloutClientResource.java similarity index 63% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/RolloutResourceClient.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtRolloutClientResource.java index aed3af7a2..acc00d6fe 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/RolloutResourceClient.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtRolloutClientResource.java @@ -8,13 +8,13 @@ */ package org.eclipse.hawkbit.mgmt.client.resource; -import org.eclipse.hawkbit.rest.resource.api.RolloutRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi; import org.springframework.cloud.netflix.feign.FeignClient; /** * Client binding for the Rollout resource of the management API. */ -@FeignClient(url = "${hawkbit.url:localhost:8080}/rest/v1/rollouts") -public interface RolloutResourceClient extends RolloutRestApi { - +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING) +public interface MgmtRolloutClientResource extends MgmtRolloutRestApi { } diff --git a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSoftwareModuleClientResource.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSoftwareModuleClientResource.java new file mode 100644 index 000000000..7a2267e24 --- /dev/null +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSoftwareModuleClientResource.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.mgmt.client.resource; + +import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi; +import org.springframework.cloud.netflix.feign.FeignClient; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; + +import feign.Param; + +/** + * Client binding for the SoftwareModule resource of the management API. + */ +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) +public interface MgmtSoftwareModuleClientResource extends MgmtSoftwareModuleRestApi { + + @Override + @RequestMapping(method = RequestMethod.POST, value = "/{softwareModuleId}/artifacts") + ResponseEntity uploadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, + @Param("file") final MultipartFile file, + @RequestParam(value = "filename", required = false) final String optionalFileName, + @RequestParam(value = "md5sum", required = false) final String md5Sum, + @RequestParam(value = "sha1sum", required = false) final String sha1Sum); +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleTypeResourceClient.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSoftwareModuleTypeClientResource.java similarity index 52% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleTypeResourceClient.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSoftwareModuleTypeClientResource.java index 46410dd6c..603e82f10 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleTypeResourceClient.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSoftwareModuleTypeClientResource.java @@ -8,13 +8,13 @@ */ package org.eclipse.hawkbit.mgmt.client.resource; -import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleTypeRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi; import org.springframework.cloud.netflix.feign.FeignClient; /** - * Client binding for the oftwareModuleType resource of the management API. + * Client binding for the SoftwareModuleType resource of the management API. */ -@FeignClient(url = "${hawkbit.url:localhost:8080}/rest/v1/softwaremoduletypes") -public interface SoftwareModuleTypeResourceClient extends SoftwareModuleTypeRestApi { - +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING) +public interface MgmtSoftwareModuleTypeClientResource extends MgmtSoftwareModuleTypeRestApi { } diff --git a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSystemClientResource.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSystemClientResource.java new file mode 100644 index 000000000..e1bbd909c --- /dev/null +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSystemClientResource.java @@ -0,0 +1,21 @@ +/** + * 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.mgmt.client.resource; + +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtSystemRestApi; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the {@link MgmtSystemRestApi}. + * + */ +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING) +public interface MgmtSystemClientResource extends MgmtSystemRestApi { +} diff --git a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSystemManagementClientResource.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSystemManagementClientResource.java new file mode 100644 index 000000000..802194fe8 --- /dev/null +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtSystemManagementClientResource.java @@ -0,0 +1,22 @@ +/** + * 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.mgmt.client.resource; + +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtSystemManagementRestApi; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the {@link MgmtSystemManagementRestApi}. + * + */ +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.SYSTEM_ADMIN_MAPPING) +public interface MgmtSystemManagementClientResource extends MgmtSystemManagementRestApi { + +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetResourceClient.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtTargetClientResource.java similarity index 63% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetResourceClient.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtTargetClientResource.java index 79385fea4..c0a0193af 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetResourceClient.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtTargetClientResource.java @@ -8,13 +8,13 @@ */ package org.eclipse.hawkbit.mgmt.client.resource; -import org.eclipse.hawkbit.rest.resource.api.TargetRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi; import org.springframework.cloud.netflix.feign.FeignClient; /** * Client binding for the Target resource of the management API. */ -@FeignClient(url = "${hawkbit.url:localhost:8080}/rest/v1/targets") -public interface TargetResourceClient extends TargetRestApi { - +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING) +public interface MgmtTargetClientResource extends MgmtTargetRestApi { } diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetTagResourceClient.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtTargetTagClientResource.java similarity index 63% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetTagResourceClient.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtTargetTagClientResource.java index 930931a87..3f9264337 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetTagResourceClient.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/MgmtTargetTagClientResource.java @@ -8,13 +8,13 @@ */ package org.eclipse.hawkbit.mgmt.client.resource; -import org.eclipse.hawkbit.rest.resource.api.TargetTagRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi; import org.springframework.cloud.netflix.feign.FeignClient; /** * Client binding for the TargetTag resource of the management API. */ -@FeignClient(url = "${hawkbit.url:localhost:8080}/rest/v1/targettags") -public interface TargetTagResourceClient extends TargetTagRestApi { - +@FeignClient(url = "${hawkbit.url:localhost:8080}" + MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING) +public interface MgmtTargetTagClientResource extends MgmtTargetTagRestApi { } diff --git a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetBuilder.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetBuilder.java new file mode 100644 index 000000000..a51d96d88 --- /dev/null +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetBuilder.java @@ -0,0 +1,135 @@ +/** + * 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.mgmt.client.resource.builder; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleAssigment; + +import com.google.common.collect.Lists; + +/** + * Builder pattern for building {@link MgmtDistributionSetRequestBodyPost}. + */ +// Exception squid:S1701 - builder pattern +@SuppressWarnings({ "squid:S1701" }) +public class DistributionSetBuilder { + + private String name; + private String version; + private String type; + private String description; + private final List modules = new ArrayList<>(); + + /** + * @param name + * the name of the distribution set + * @return the builder itself + */ + public DistributionSetBuilder name(final String name) { + this.name = name; + return this; + } + + public DistributionSetBuilder moduleByID(final Long id) { + final MgmtSoftwareModuleAssigment softwareModuleAssigmentRest = new MgmtSoftwareModuleAssigment(); + softwareModuleAssigmentRest.setId(id); + modules.add(softwareModuleAssigmentRest); + return this; + } + + /** + * @param version + * the version of the distribution set + * @return the builder itself + */ + public DistributionSetBuilder version(final String version) { + this.version = version; + return this; + } + + /** + * @param type + * the distribution set type name for this distribution set + * @return the builder itself + */ + public DistributionSetBuilder type(final String type) { + this.type = type; + return this; + } + + /** + * @param description + * the description + * @return the builder itself + */ + public DistributionSetBuilder description(final String description) { + this.description = description; + return this; + } + + /** + * Builds a list with a single entry of + * {@link MgmtDistributionSetRequestBodyPost} which can directly be used to + * post on the RESTful-API. + * + * @return a single entry list of {@link MgmtDistributionSetRequestBodyPost} + */ + public List build() { + return Lists.newArrayList(doBuild("")); + } + + /** + * Builds a list of multiple {@link MgmtDistributionSetRequestBodyPost} to + * create multiple distribution sets at once. An increasing number will be + * used for version of the distribution set. The name and type will remain + * the same. + * + * @param count + * the amount of distribution sets body which should be created + * @return a list of {@link MgmtDistributionSetRequestBodyPost} + */ + public List buildAsList(final int count) { + return buildAsList(0, count); + } + + /** + * Builds a list of multiple {@link MgmtDistributionSetRequestBodyPost} to + * create multiple distribution sets at once. An increasing number will be + * used for version of the distribution set starting from given offset. The + * name and type will remain the same. + * + * @param count + * the amount of distribution sets body which should be created + * @param offset + * for for index start + * @return a list of {@link MgmtDistributionSetRequestBodyPost} + */ + public List buildAsList(final int offset, final int count) { + final ArrayList bodyList = Lists.newArrayList(); + for (int index = offset; index < count + offset; index++) { + bodyList.add(doBuild(String.valueOf(index))); + } + + return bodyList; + } + + private MgmtDistributionSetRequestBodyPost doBuild(final String suffix) { + final MgmtDistributionSetRequestBodyPost body = new MgmtDistributionSetRequestBodyPost(); + body.setName(name); + body.setVersion(version + suffix); + body.setType(type); + body.setDescription(description); + body.setModules(modules); + return body; + } + +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java similarity index 55% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java index ff03bb442..028060f37 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java @@ -11,23 +11,25 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder; import java.util.ArrayList; import java.util.List; -import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeAssigmentRest; +import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeAssigment; import com.google.common.collect.Lists; /** * - * Builder pattern for building {@link DistributionSetTypeRequestBodyPost}. + * Builder pattern for building {@link MgmtDistributionSetTypeRequestBodyPost}. * */ // Exception squid:S1701 - builder pattern @SuppressWarnings({ "squid:S1701" }) public class DistributionSetTypeBuilder { + private String key; private String name; - private final List mandatorymodules = Lists.newArrayList(); - private final List optionalmodules = Lists.newArrayList(); + private String description; + private final List mandatorymodules = Lists.newArrayList(); + private final List optionalmodules = Lists.newArrayList(); /** * @param key @@ -49,6 +51,16 @@ public class DistributionSetTypeBuilder { return this; } + /** + * @param description + * the description + * @return the builder itself + */ + public DistributionSetTypeBuilder description(final String description) { + this.description = description; + return this; + } + /** * @param softwareModuleTypeIds * the IDs of the software module types which should be mandatory @@ -57,7 +69,7 @@ public class DistributionSetTypeBuilder { */ public DistributionSetTypeBuilder mandatorymodules(final Long... softwareModuleTypeIds) { for (final Long id : softwareModuleTypeIds) { - final SoftwareModuleTypeAssigmentRest softwareModuleTypeAssigmentRest = new SoftwareModuleTypeAssigmentRest(); + final MgmtSoftwareModuleTypeAssigment softwareModuleTypeAssigmentRest = new MgmtSoftwareModuleTypeAssigment(); softwareModuleTypeAssigmentRest.setId(id); this.mandatorymodules.add(softwareModuleTypeAssigmentRest); } @@ -73,7 +85,7 @@ public class DistributionSetTypeBuilder { */ public DistributionSetTypeBuilder optionalmodules(final Long... softwareModuleTypeIds) { for (final Long id : softwareModuleTypeIds) { - final SoftwareModuleTypeAssigmentRest softwareModuleTypeAssigmentRest = new SoftwareModuleTypeAssigmentRest(); + final MgmtSoftwareModuleTypeAssigment softwareModuleTypeAssigmentRest = new MgmtSoftwareModuleTypeAssigment(); softwareModuleTypeAssigmentRest.setId(id); this.optionalmodules.add(softwareModuleTypeAssigmentRest); } @@ -82,39 +94,41 @@ public class DistributionSetTypeBuilder { /** * Builds a list with a single entry of - * {@link DistributionSetTypeRequestBodyPost} which can directly be used in - * the RESTful-API. + * {@link MgmtDistributionSetTypeRequestBodyPost} which can directly be used + * in the RESTful-API. * - * @return a single entry list of {@link DistributionSetTypeRequestBodyPost} + * @return a single entry list of + * {@link MgmtDistributionSetTypeRequestBodyPost} */ - public List build() { - return Lists.newArrayList(doBuild(name, key)); + public List build() { + return Lists.newArrayList(doBuild("")); } /** - * Builds a list of multiple {@link DistributionSetTypeRequestBodyPost} to - * create multiple distribution set types at once. An increasing number will - * be added to the name and key of the distribution set type. The optional - * and mandatory software module types will remain the same. + * Builds a list of multiple {@link MgmtDistributionSetTypeRequestBodyPost} + * to create multiple distribution set types at once. An increasing number + * will be added to the name and key of the distribution set type. The + * optional and mandatory software module types will remain the same. * * @param count * the amount of distribution sets type body which should be * created - * @return a list of {@link DistributionSetTypeRequestBodyPost} + * @return a list of {@link MgmtDistributionSetTypeRequestBodyPost} */ - public List buildAsList(final int count) { - final ArrayList bodyList = Lists.newArrayList(); + public List buildAsList(final int count) { + final ArrayList bodyList = Lists.newArrayList(); for (int index = 0; index < count; index++) { - bodyList.add(doBuild(name + index, key + index)); + bodyList.add(doBuild(String.valueOf(index))); } return bodyList; } - private DistributionSetTypeRequestBodyPost doBuild(final String prefixName, final String prefixKey) { - final DistributionSetTypeRequestBodyPost body = new DistributionSetTypeRequestBodyPost(); - body.setKey(prefixKey); - body.setName(prefixName); + private MgmtDistributionSetTypeRequestBodyPost doBuild(final String suffix) { + final MgmtDistributionSetTypeRequestBodyPost body = new MgmtDistributionSetTypeRequestBodyPost(); + body.setKey(key + suffix); + body.setName(name + suffix); + body.setDescription(description); body.setMandatorymodules(mandatorymodules); body.setOptionalmodules(optionalmodules); return body; diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java similarity index 76% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java index e9203fc39..02ebe2de3 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java @@ -8,13 +8,13 @@ */ package org.eclipse.hawkbit.mgmt.client.resource.builder; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutCondition; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutCondition.Condition; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutRestRequestBody; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition.Condition; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBody; /** * - * Builder pattern for building {@link RolloutRestRequestBody}. + * Builder pattern for building {@link MgmtRolloutRestRequestBody}. * */ // Exception squid:S1701 - builder pattern @@ -27,6 +27,7 @@ public class RolloutBuilder { private long distributionSetId; private String successThreshold; private String errorThreshold; + private String description; /** * @param name @@ -59,6 +60,16 @@ public class RolloutBuilder { return this; } + /** + * @param description + * the description + * @return the builder itself + */ + public RolloutBuilder description(final String description) { + this.description = description; + return this; + } + /** * @param distributionSetId * the ID of the distribution set to assign to the target in the @@ -97,18 +108,19 @@ public class RolloutBuilder { * * @return the rest request body for creating a rollout */ - public RolloutRestRequestBody build() { + public MgmtRolloutRestRequestBody build() { return doBuild(); } - private RolloutRestRequestBody doBuild() { - final RolloutRestRequestBody body = new RolloutRestRequestBody(); + private MgmtRolloutRestRequestBody doBuild() { + final MgmtRolloutRestRequestBody body = new MgmtRolloutRestRequestBody(); body.setName(name); body.setAmountGroups(groupSize); body.setTargetFilterQuery(targetFilterQuery); body.setDistributionSetId(distributionSetId); - body.setSuccessCondition(new RolloutCondition(Condition.THRESHOLD, successThreshold)); - body.setErrorCondition(new RolloutCondition(Condition.THRESHOLD, errorThreshold)); + body.setDescription(description); + body.setSuccessCondition(new MgmtRolloutCondition(Condition.THRESHOLD, successThreshold)); + body.setErrorCondition(new MgmtRolloutCondition(Condition.THRESHOLD, errorThreshold)); return body; } diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleAssigmentBuilder.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleAssigmentBuilder.java similarity index 65% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleAssigmentBuilder.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleAssigmentBuilder.java index 8d69db619..b9fbcb498 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleAssigmentBuilder.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleAssigmentBuilder.java @@ -11,13 +11,15 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder; import java.util.ArrayList; import java.util.List; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleAssigmentRest; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleAssigment; /** * - * Builder pattern for building {@link SoftwareModuleAssigmentRest}. + * Builder pattern for building {@link MgmtSoftwareModuleAssigment}. * */ +// Exception squid:S1701 - builder pattern +@SuppressWarnings({ "squid:S1701" }) public class SoftwareModuleAssigmentBuilder { private final List ids; @@ -37,15 +39,15 @@ public class SoftwareModuleAssigmentBuilder { } /** - * Builds a list with a single entry of {@link SoftwareModuleAssigmentRest} + * Builds a list with a single entry of {@link MgmtSoftwareModuleAssigment} * which can directly be used in the RESTful-API. * - * @return a single entry list of {@link SoftwareModuleAssigmentRest} + * @return a single entry list of {@link MgmtSoftwareModuleAssigment} */ - public List build() { - final List softwareModuleAssigmentRestList = new ArrayList<>(); + public List build() { + final List softwareModuleAssigmentRestList = new ArrayList<>(); for (final Long id : ids) { - final SoftwareModuleAssigmentRest softwareModuleAssigmentRest = new SoftwareModuleAssigmentRest(); + final MgmtSoftwareModuleAssigment softwareModuleAssigmentRest = new MgmtSoftwareModuleAssigment(); softwareModuleAssigmentRest.setId(id); softwareModuleAssigmentRestList.add(softwareModuleAssigmentRest); } diff --git a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleBuilder.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleBuilder.java new file mode 100644 index 000000000..db7941bfc --- /dev/null +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleBuilder.java @@ -0,0 +1,125 @@ +/** + * 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.mgmt.client.resource.builder; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost; + +import com.google.common.collect.Lists; + +/** + * + * Builder pattern for building {@link MgmtSoftwareModuleRequestBodyPost}. + * + */ +// Exception squid:S1701 - builder pattern +@SuppressWarnings({ "squid:S1701" }) +public class SoftwareModuleBuilder { + + private String name; + private String version; + private String type; + private String vendor; + private String description; + + /** + * @param name + * the name of the software module + * @return the builder itself + */ + public SoftwareModuleBuilder name(final String name) { + this.name = name; + return this; + } + + /** + * @param version + * the version of the software module + * @return the builder itsefl + */ + public SoftwareModuleBuilder version(final String version) { + this.version = version; + return this; + } + + /** + * @param type + * the key of the software module type to be used for this + * software module + * @return the builder itself + */ + public SoftwareModuleBuilder type(final String type) { + this.type = type; + return this; + } + + /** + * @param vendor + * the vendor + * @return the builder itself + */ + public SoftwareModuleBuilder vendor(final String vendor) { + this.vendor = vendor; + return this; + } + + /** + * @param description + * the description + * @return the builder itself + */ + public SoftwareModuleBuilder description(final String description) { + this.description = description; + return this; + } + + /** + * Builds a list with a single entry of + * {@link MgmtSoftwareModuleRequestBodyPost} which can directly be used in + * the RESTful-API. + * + * @return a single entry list of {@link MgmtSoftwareModuleRequestBodyPost} + */ + public List build() { + return Lists.newArrayList(doBuild("")); + } + + /** + * Builds a list of multiple {@link MgmtSoftwareModuleRequestBodyPost} to + * create multiple software module at once. An increasing number will be + * added to the version of the software module. The name and type will + * remain the same. + * + * @param count + * the amount of software module body which should be created + * @return a list of {@link MgmtDistributionSetTypeRequestBodyPost} + */ + public List buildAsList(final int count) { + final ArrayList bodyList = Lists.newArrayList(); + for (int index = 0; index < count; index++) { + bodyList.add(doBuild(String.valueOf(index))); + } + + return bodyList; + } + + private MgmtSoftwareModuleRequestBodyPost doBuild(final String suffix) { + final MgmtSoftwareModuleRequestBodyPost body = new MgmtSoftwareModuleRequestBodyPost(); + body.setName(name); + body.setVersion(version + suffix); + body.setType(type); + body.setVendor(vendor); + body.setDescription(description); + return body; + } + +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java similarity index 59% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java index e27cedc72..7807d0f11 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java @@ -11,14 +11,14 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder; import java.util.ArrayList; import java.util.List; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost; import com.google.common.collect.Lists; /** * - * Builder pattern for building {@link SoftwareModuleRequestBodyPost}. + * Builder pattern for building {@link MgmtSoftwareModuleRequestBodyPost}. * */ // Exception squid:S1701 - builder pattern @@ -62,37 +62,38 @@ public class SoftwareModuleTypeBuilder { /** * Builds a list with a single entry of - * {@link SoftwareModuleTypeRequestBodyPost} which can directly be used in - * the RESTful-API. + * {@link MgmtSoftwareModuleTypeRequestBodyPost} which can directly be used + * in the RESTful-API. * - * @return a single entry list of {@link SoftwareModuleTypeRequestBodyPost} + * @return a single entry list of + * {@link MgmtSoftwareModuleTypeRequestBodyPost} */ - public List build() { - return Lists.newArrayList(doBuild(key, name)); + public List build() { + return Lists.newArrayList(doBuild("")); } /** - * Builds a list of multiple {@link SoftwareModuleTypeRequestBodyPost} to - * create multiple software module types at once. An increasing number will - * be added to the name and key of the software module type. + * Builds a list of multiple {@link MgmtSoftwareModuleTypeRequestBodyPost} + * to create multiple software module types at once. An increasing number + * will be added to the name and key of the software module type. * * @param count * the amount of software module type bodies which should be * created - * @return a list of {@link SoftwareModuleTypeRequestBodyPost} + * @return a list of {@link MgmtSoftwareModuleTypeRequestBodyPost} */ - public List buildAsList(final int count) { - final ArrayList bodyList = Lists.newArrayList(); + public List buildAsList(final int count) { + final ArrayList bodyList = Lists.newArrayList(); for (int index = 0; index < count; index++) { - bodyList.add(doBuild(key + index, name + index)); + bodyList.add(doBuild(String.valueOf(index))); } return bodyList; } - private SoftwareModuleTypeRequestBodyPost doBuild(final String prefixKey, final String prefixName) { - final SoftwareModuleTypeRequestBodyPost body = new SoftwareModuleTypeRequestBodyPost(); - body.setKey(prefixKey); - body.setName(prefixName); + private MgmtSoftwareModuleTypeRequestBodyPost doBuild(final String suffix) { + final MgmtSoftwareModuleTypeRequestBodyPost body = new MgmtSoftwareModuleTypeRequestBodyPost(); + body.setKey(key + suffix); + body.setName(name + suffix); body.setDescription(description); body.setMaxAssignments(maxAssignments); return body; diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java similarity index 66% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java rename to examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java index 32f7c1107..ce13602df 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java @@ -11,12 +11,12 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder; import java.util.ArrayList; import java.util.List; -import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut; import com.google.common.collect.Lists; /** - * Builder pattern for building {@link TagRequestBodyPut}. + * Builder pattern for building {@link MgmtTagRequestBodyPut}. * */ // Exception squid:S1701 - builder pattern @@ -58,26 +58,26 @@ public class TagBuilder { } /** - * Builds a list with a single entry of {@link TagRequestBodyPut} which can - * directly be used in the RESTful-API. + * Builds a list with a single entry of {@link MgmtTagRequestBodyPut} which + * can directly be used in the RESTful-API. * - * @return a single entry list of {@link TagRequestBodyPut} + * @return a single entry list of {@link MgmtTagRequestBodyPut} */ - public List build() { + public List build() { return Lists.newArrayList(doBuild(name)); } /** - * Builds a list of multiple {@link TagRequestBodyPut} to create multiple - * tags at once. An increasing number will be added to the name of the tag. - * The color and description will remain the same. + * Builds a list of multiple {@link MgmtTagRequestBodyPut} to create + * multiple tags at once. An increasing number will be added to the name of + * the tag. The color and description will remain the same. * * @param count * the amount of distribution sets body which should be created - * @return a list of {@link TagRequestBodyPut} + * @return a list of {@link MgmtTagRequestBodyPut} */ - public List buildAsList(final int count) { - final ArrayList bodyList = Lists.newArrayList(); + public List buildAsList(final int count) { + final ArrayList bodyList = Lists.newArrayList(); for (int index = 0; index < count; index++) { bodyList.add(doBuild(name + index)); } @@ -85,8 +85,8 @@ public class TagBuilder { return bodyList; } - private TagRequestBodyPut doBuild(final String prefixName) { - final TagRequestBodyPut body = new TagRequestBodyPut(); + private MgmtTagRequestBodyPut doBuild(final String prefixName) { + final MgmtTagRequestBodyPut body = new MgmtTagRequestBodyPut(); body.setName(prefixName); body.setDescription(description); body.setColour(color); diff --git a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java new file mode 100644 index 000000000..5fbcd0313 --- /dev/null +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java @@ -0,0 +1,130 @@ +/** + * 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.mgmt.client.resource.builder; + +import java.util.List; + +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody; + +import com.google.common.collect.Lists; + +/** + * + * Builder pattern for building {@link MgmtTargetRequestBody}. + * + */ +// Exception squid:S1701 - builder pattern +@SuppressWarnings({ "squid:S1701" }) +public class TargetBuilder { + + private String controllerId; + private String name; + private String description; + private String address; + + /** + * @param controllerId + * the ID of the controller/target + * @return the builder itself + */ + public TargetBuilder controllerId(final String controllerId) { + this.controllerId = controllerId; + return this; + } + + /** + * @param name + * the name of the target + * @return the builder itself + */ + public TargetBuilder name(final String name) { + this.name = name; + return this; + } + + /** + * @param address + * the address of the target + * @return the builder itself + */ + public TargetBuilder address(final String address) { + this.address = address; + return this; + } + + /** + * @param description + * the description of the target + * @return the builder itself + */ + public TargetBuilder description(final String description) { + this.description = description; + return this; + } + + /** + * Builds a list with a single entry of {@link MgmtTargetRequestBody} which + * can directly be used in the RESTful-API. + * + * @return a single entry list of {@link MgmtTargetRequestBody} + */ + public List build() { + return Lists.newArrayList(doBuild("")); + } + + /** + * Builds a list of multiple {@link MgmtTargetRequestBody} to create + * multiple targets at once. An increasing number will be added to the + * controllerId and name of the target. The description will remain. + * + * @param count + * the amount of target bodies which should be created + * @param offset + * for + * @return a list of {@link MgmtSoftwareModuleTypeRequestBodyPost} + */ + public List buildAsList(final int count) { + + return buildAsList(0, count); + } + + /** + * Builds a list of multiple {@link MgmtTargetRequestBody} to create + * multiple targets at once. An increasing number will be added to the + * controllerId and name of the target starting from the provided offset. + * The description will remain. + * + * @param count + * the amount of target bodies which should be created + * @param offset + * for for index start + * @return a list of {@link MgmtSoftwareModuleTypeRequestBodyPost} + */ + public List buildAsList(final int offset, final int count) { + final List bodyList = Lists.newArrayList(); + for (int index = offset; index < count + offset; index++) { + bodyList.add(doBuild(String.valueOf(index))); + } + return bodyList; + } + + private MgmtTargetRequestBody doBuild(final String suffix) { + final MgmtTargetRequestBody body = new MgmtTargetRequestBody(); + body.setControllerId(controllerId + suffix); + if (name == null) { + name = controllerId; + } + body.setName(name + suffix); + body.setDescription(description); + body.setAddress(address); + return body; + } + +} diff --git a/examples/hawkbit-example-mgmt-simulator/.gitignore b/examples/hawkbit-example-mgmt-simulator/.gitignore new file mode 100644 index 000000000..b5c3eb864 --- /dev/null +++ b/examples/hawkbit-example-mgmt-simulator/.gitignore @@ -0,0 +1,4 @@ +/target/ +/bin/ +/.apt_generated/ +/.springBeans diff --git a/examples/hawkbit-mgmt-api-client/README.md b/examples/hawkbit-example-mgmt-simulator/README.md similarity index 62% rename from examples/hawkbit-mgmt-api-client/README.md rename to examples/hawkbit-example-mgmt-simulator/README.md index ac8e7a4cd..925df8041 100644 --- a/examples/hawkbit-mgmt-api-client/README.md +++ b/examples/hawkbit-example-mgmt-simulator/README.md @@ -1,6 +1,6 @@ -# hawkBit Management API example client +# Eclipse.IoT hawkBit - Example Management Feign Client -Example client that shows how to efficiently use the hawkBit management API. +Example Spring Boot client that shows how to efficiently use the hawkBit Example Management Feign Client and the hawkBit Management API. Powered by [Feign](https://github.com/Netflix/feign). @@ -10,13 +10,13 @@ Run getting started example - $ java -jar hawkbit-mgmt-api-client-#version#.jar + $ java -jar hawkbit-example-mgmt-simulator-#version#.jar Run create and start rollout example - $ java -jar hawkbit-mgmt-api-client-#version#.jar --createrollout + $ java -jar hawkbit-example-mgmt-simulator-#version#.jar --createrollout ## This example shows @@ -28,7 +28,7 @@ In getting started example: * creating software modules * assigning software modules to distribution sets -In rollout mode: +In create rollout example: * creating software modules type * creating distribution set type * creating distribution sets diff --git a/examples/hawkbit-mgmt-api-client/pom.xml b/examples/hawkbit-example-mgmt-simulator/pom.xml similarity index 87% rename from examples/hawkbit-mgmt-api-client/pom.xml rename to examples/hawkbit-example-mgmt-simulator/pom.xml index 77e35df83..469290dfc 100644 --- a/examples/hawkbit-mgmt-api-client/pom.xml +++ b/examples/hawkbit-example-mgmt-simulator/pom.xml @@ -17,8 +17,8 @@ 0.2.0-SNAPSHOT jar - hawkbit-mgmt-api-client - hawkBit :: Management API example client + hawkbit-example-mgmt-simulator + hawkBit-example :: Management feign client simulator @@ -57,14 +57,20 @@ org.eclipse.hawkbit - hawkbit-rest-api + hawkbit-example-mgmt-feign-client ${project.version} com.netflix.feign feign-core - - 8.14.2 + + + com.netflix.feign + feign-jackson + + + com.fasterxml.jackson.core + jackson-databind hibernate-validator @@ -82,11 +88,6 @@ org.springframework.boot spring-boot-starter-logging - - com.google.collections - google-collections - 1.0-rc2 - org.springframework.boot spring-boot-configuration-processor diff --git a/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/Application.java b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/Application.java new file mode 100644 index 000000000..ac65455b5 --- /dev/null +++ b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/Application.java @@ -0,0 +1,124 @@ +/** + * 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.mgmt.client; + +import org.eclipse.hawkbit.feign.core.client.FeignClientConfiguration; +import org.eclipse.hawkbit.feign.core.client.IgnoreMultipleConsumersProducersSpringMvcContract; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtDistributionSetClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtRolloutClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtSoftwareModuleClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtTargetClientResource; +import org.eclipse.hawkbit.mgmt.client.scenarios.ConfigurableScenario; +import org.eclipse.hawkbit.mgmt.client.scenarios.CreateStartedRolloutExample; +import org.eclipse.hawkbit.mgmt.client.scenarios.upload.FeignMultipartEncoder; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.netflix.feign.EnableFeignClients; +import org.springframework.cloud.netflix.feign.support.ResponseEntityDecoder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.hateoas.hal.Jackson2HalModule; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import feign.Feign; +import feign.Logger; +import feign.auth.BasicAuthRequestInterceptor; +import feign.jackson.JacksonDecoder; +import feign.slf4j.Slf4jLogger; + +@SpringBootApplication +@EnableFeignClients("org.eclipse.hawkbit.mgmt.client.resource") +@EnableConfigurationProperties(ClientConfigurationProperties.class) +@Configuration +@AutoConfigureAfter(FeignClientConfiguration.class) +@Import(FeignClientConfiguration.class) +public class Application implements CommandLineRunner { + + @Autowired + private ClientConfigurationProperties configuration; + + @Autowired + private ConfigurableScenario configuredScenario; + + @Autowired + private CreateStartedRolloutExample gettingStartedRolloutScenario; + + public static void main(final String[] args) { + new SpringApplicationBuilder().showBanner(false).sources(Application.class).run(args); + } + + @Override + public void run(final String... args) throws Exception { + if (containsArg("--createrollout", args)) { + // run the create and start rollout example + gettingStartedRolloutScenario.run(); + } else { + // run the configured scenario from properties + configuredScenario.run(); + } + } + + @Bean + public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { + return new BasicAuthRequestInterceptor(configuration.getUsername(), configuration.getPassword()); + } + + @Bean + public ConfigurableScenario configurableScenario(final MgmtDistributionSetClientResource distributionSetResource, + @Qualifier("mgmtSoftwareModuleClientResource") final MgmtSoftwareModuleClientResource softwareModuleResource, + @Qualifier("uploadSoftwareModule") final MgmtSoftwareModuleClientResource uploadSoftwareModule, + final MgmtTargetClientResource targetResource, final MgmtRolloutClientResource rolloutResource, + final ClientConfigurationProperties clientConfigurationProperties) { + return new ConfigurableScenario(distributionSetResource, softwareModuleResource, uploadSoftwareModule, + targetResource, rolloutResource, clientConfigurationProperties); + } + + @Bean + public CreateStartedRolloutExample createStartedRolloutExample() { + return new CreateStartedRolloutExample(); + } + + @Bean + public Logger.Level feignLoggerLevel() { + return Logger.Level.FULL; + } + + @Bean + public MgmtSoftwareModuleClientResource uploadSoftwareModule() { + final ObjectMapper mapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .registerModule(new Jackson2HalModule()); + + return Feign.builder().contract(new IgnoreMultipleConsumersProducersSpringMvcContract()) + .requestInterceptor( + new BasicAuthRequestInterceptor(configuration.getUsername(), configuration.getPassword())) + .logger(new Slf4jLogger()).encoder(new FeignMultipartEncoder()) + .decoder(new ResponseEntityDecoder(new JacksonDecoder(mapper))) + .target(MgmtSoftwareModuleClientResource.class, + configuration.getUrl() + MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING); + } + + private static boolean containsArg(final String containsArg, final String... args) { + for (final String arg : args) { + if (arg.equalsIgnoreCase(containsArg)) { + return true; + } + } + return false; + } +} diff --git a/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java new file mode 100644 index 000000000..83a0844d4 --- /dev/null +++ b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java @@ -0,0 +1,199 @@ +/** + * 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.mgmt.client; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration bean which holds the configuration of the client e.g. the base + * URL of the hawkbit-server and the credentials to use the RESTful Management + * API. + */ +@ConfigurationProperties(prefix = "hawkbit") +public class ClientConfigurationProperties { + + /** + * Update server URI. + */ + private String url = "localhost:8080"; + + /** + * Update server user name. + */ + private String username = "admin"; + + /** + * Update server password. + */ + private String password = "admin"; // NOSONAR this password is only used for + // examples + + private final List scenarios = new ArrayList<>(); + + /** + * Simulation {@link Scenario}. + * + */ + public static class Scenario { + private boolean cleanRepository; + private int targets = 100; + private int distributionSets = 10; + private int appModulesPerDistributionSet = 2; + private String dsName = "Package"; + private String smSwName = "Application"; + private String smFwName = "Firmware"; + private String targetName = "Device"; + private int artifactsPerSM = 1; + private String targetAddress = "amqp:/simulator.replyTo"; + private boolean runRollouts = true; + private int rolloutDeploymentGroups = 4; + + /** + * Artifact size. Values can use the suffixed "MB" or "KB" to indicate a + * Megabyte or Kilobyte size. + */ + private String artifactSize = "1MB"; + + public boolean isCleanRepository() { + return cleanRepository; + } + + public void setCleanRepository(final boolean cleanRepository) { + this.cleanRepository = cleanRepository; + } + + public int getRolloutDeploymentGroups() { + return rolloutDeploymentGroups; + } + + public void setRolloutDeploymentGroups(final int rolloutDeploymentGroups) { + this.rolloutDeploymentGroups = rolloutDeploymentGroups; + } + + public boolean isRunRollouts() { + return runRollouts; + } + + public void setRunRollouts(final boolean runRollouts) { + this.runRollouts = runRollouts; + } + + public String getTargetAddress() { + return targetAddress; + } + + public void setTargetAddress(final String targetAddress) { + this.targetAddress = targetAddress; + } + + public int getArtifactsPerSM() { + return artifactsPerSM; + } + + public void setArtifactsPerSM(final int artifactsPerSM) { + this.artifactsPerSM = artifactsPerSM; + } + + public String getArtifactSize() { + return artifactSize; + } + + public void setArtifactSize(final String artifactSize) { + this.artifactSize = artifactSize; + } + + public String getTargetName() { + return targetName; + } + + public void setTargetName(final String targetName) { + this.targetName = targetName; + } + + public String getDsName() { + return dsName; + } + + public void setDsName(final String dsName) { + this.dsName = dsName; + } + + public String getSmSwName() { + return smSwName; + } + + public void setSmSwName(final String smSwName) { + this.smSwName = smSwName; + } + + public String getSmFwName() { + return smFwName; + } + + public void setSmFwName(final String smFwName) { + this.smFwName = smFwName; + } + + public int getTargets() { + return targets; + } + + public int getDistributionSets() { + return distributionSets; + } + + public int getAppModulesPerDistributionSet() { + return appModulesPerDistributionSet; + } + + public void setTargets(final int targets) { + this.targets = targets; + } + + public void setDistributionSets(final int distributionSets) { + this.distributionSets = distributionSets; + } + + public void setAppModulesPerDistributionSet(final int appModulesPerDistributionSet) { + this.appModulesPerDistributionSet = appModulesPerDistributionSet; + } + + } + + public List getScenarios() { + return scenarios; + } + + public String getUrl() { + return url; + } + + public void setUrl(final String url) { + this.url = url; + } + + public String getUsername() { + return username; + } + + public void setUsername(final String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(final String password) { + this.password = password; + } +} diff --git a/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/ConfigurableScenario.java b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/ConfigurableScenario.java new file mode 100644 index 000000000..a09459e07 --- /dev/null +++ b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/ConfigurableScenario.java @@ -0,0 +1,242 @@ +/** + * 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.mgmt.client.scenarios; + +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +import org.eclipse.hawkbit.mgmt.client.ClientConfigurationProperties; +import org.eclipse.hawkbit.mgmt.client.ClientConfigurationProperties.Scenario; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtDistributionSetClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtRolloutClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtSoftwareModuleClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtTargetClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetBuilder; +import org.eclipse.hawkbit.mgmt.client.resource.builder.RolloutBuilder; +import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleAssigmentBuilder; +import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleBuilder; +import org.eclipse.hawkbit.mgmt.client.resource.builder.TargetBuilder; +import org.eclipse.hawkbit.mgmt.client.scenarios.upload.ArtifactFile; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; + +/** + * + * A configurable scenario which runs the configured scenarios. + * + * @see {@link ClientConfigurationProperties#getScenarios()} + * + */ +public class ConfigurableScenario { + + private static final int PAGE_SIZE = 100; + + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurableScenario.class); + + private final MgmtDistributionSetClientResource distributionSetResource; + + private final MgmtSoftwareModuleClientResource softwareModuleResource; + + private final MgmtSoftwareModuleClientResource uploadSoftwareModule; + + private final MgmtTargetClientResource targetResource; + + private final MgmtRolloutClientResource rolloutResource; + + private final ClientConfigurationProperties clientConfigurationProperties; + + public ConfigurableScenario(final MgmtDistributionSetClientResource distributionSetResource, + @Qualifier("mgmtSoftwareModuleClientResource") final MgmtSoftwareModuleClientResource softwareModuleResource, + @Qualifier("uploadSoftwareModule") final MgmtSoftwareModuleClientResource uploadSoftwareModule, + final MgmtTargetClientResource targetResource, final MgmtRolloutClientResource rolloutResource, + final ClientConfigurationProperties clientConfigurationProperties) { + this.distributionSetResource = distributionSetResource; + this.softwareModuleResource = softwareModuleResource; + this.uploadSoftwareModule = uploadSoftwareModule; + this.targetResource = targetResource; + this.rolloutResource = rolloutResource; + this.clientConfigurationProperties = clientConfigurationProperties; + } + + /** + * Run the default getting started scenario. + */ + public void run() { + + LOGGER.info("Running Configurable Scenario..."); + + clientConfigurationProperties.getScenarios().forEach(this::createScenario); + } + + private void createScenario(final Scenario scenario) { + if (scenario.isCleanRepository()) { + cleanRepository(); + } + + createTargets(scenario); + createDistributionSets(scenario); + + if (scenario.isRunRollouts()) { + runRollouts(scenario); + } + } + + private void cleanRepository() { + LOGGER.info("Cleaning repository"); + deleteTargets(); + deleteRollouts(); + deleteDistributionSets(); + deleteSoftwareModules(); + LOGGER.info("Cleaning repository -> Done"); + } + + private void deleteRollouts() { + // TODO: complete this as soon as rollouts can be deleted + + } + + private void deleteSoftwareModules() { + PagedList modules; + do { + modules = softwareModuleResource.getSoftwareModules(0, PAGE_SIZE, null, null).getBody(); + modules.getContent().forEach(module -> softwareModuleResource.deleteSoftwareModule(module.getModuleId())); + } while (modules.getTotal() > PAGE_SIZE); + } + + private void deleteDistributionSets() { + PagedList distributionSets; + do { + distributionSets = distributionSetResource.getDistributionSets(0, PAGE_SIZE, null, null).getBody(); + distributionSets.getContent().forEach(set -> distributionSetResource.deleteDistributionSet(set.getDsId())); + } while (distributionSets.getTotal() > PAGE_SIZE); + } + + private void deleteTargets() { + PagedList targets; + do { + targets = targetResource.getTargets(0, PAGE_SIZE, null, null).getBody(); + targets.getContent().forEach(target -> targetResource.deleteTarget(target.getControllerId())); + } while (targets.getTotal() > PAGE_SIZE); + } + + private void runRollouts(final Scenario scenario) { + distributionSetResource.getDistributionSets(0, scenario.getDistributionSets(), null, null).getBody() + .getContent().forEach(set -> runRollout(set, scenario)); + + } + + private void runRollout(final MgmtDistributionSet set, final Scenario scenario) { + LOGGER.info("Run rollout for set {}", set.getDsId()); + // create a Rollout + final MgmtRolloutResponseBody rolloutResponseBody = rolloutResource + .create(new RolloutBuilder().name("Rollout" + set.getName() + set.getVersion()) + .groupSize(scenario.getRolloutDeploymentGroups()).targetFilterQuery("name==*") + .distributionSetId(set.getDsId()).successThreshold("80").errorThreshold("5").build()) + .getBody(); + + // start the created Rollout + rolloutResource.start(rolloutResponseBody.getRolloutId(), true); + + // wait until rollout is complete + do { + try { + TimeUnit.SECONDS.sleep(35); + } catch (final InterruptedException e) { + LOGGER.warn("Interrupted!"); + Thread.currentThread().interrupt(); + } + } while (targetResource.getTargets(0, 1, null, "updateStatus==IN_SYNC").getBody().getTotal() < scenario + .getTargets()); + LOGGER.info("Run rollout for set {} -> Done", set.getDsId()); + } + + private void createDistributionSets(final Scenario scenario) { + LOGGER.info("Creating {} distribution sets", scenario.getDistributionSets()); + final byte[] artifact = generateArtifact(scenario); + + distributionSetResource.createDistributionSets(new DistributionSetBuilder().name(scenario.getDsName()) + .type("os_app").version("1.0.").buildAsList(scenario.getDistributionSets())).getBody() + .forEach(dsSet -> { + final List modules = addModules(scenario, dsSet, artifact); + + final SoftwareModuleAssigmentBuilder assign = new SoftwareModuleAssigmentBuilder(); + modules.forEach(module -> assign.id(module.getModuleId())); + distributionSetResource.assignSoftwareModules(dsSet.getDsId(), assign.build()); + }); + + LOGGER.info("Creating {} distribution sets -> Done", scenario.getDistributionSets()); + } + + private List addModules(final Scenario scenario, final MgmtDistributionSet dsSet, + final byte[] artifact) { + final List modules = softwareModuleResource + .createSoftwareModules(new SoftwareModuleBuilder().name(scenario.getSmFwName() + "-os") + .version(dsSet.getVersion()).type("os").build()) + .getBody(); + modules.addAll(softwareModuleResource.createSoftwareModules( + new SoftwareModuleBuilder().name(scenario.getSmSwName() + "-app").version(dsSet.getVersion() + ".") + .type("application").buildAsList(scenario.getAppModulesPerDistributionSet())) + .getBody()); + + for (int x = 0; x < scenario.getArtifactsPerSM(); x++) { + modules.forEach(module -> { + final ArtifactFile file = new ArtifactFile("dummyfile.dummy", null, "multipart/form-data", artifact); + uploadSoftwareModule.uploadArtifact(module.getModuleId(), file, null, null, null); + }); + } + + return modules; + } + + private static byte[] generateArtifact(final Scenario scenario) { + + // Exception squid:S2245 - not used for cryptographic function + @SuppressWarnings("squid:S2245") + final Random random = new Random(); + + // create byte array + final byte[] nbyte = new byte[parseSize(scenario.getArtifactSize())]; + + // put the next byte in the array + random.nextBytes(nbyte); + + return nbyte; + } + + private void createTargets(final Scenario scenario) { + LOGGER.info("Creating {} targets", scenario.getTargets()); + + for (int i = 0; i < (scenario.getTargets() / PAGE_SIZE); i++) { + targetResource.createTargets( + new TargetBuilder().controllerId(scenario.getTargetName()).address(scenario.getTargetAddress()) + .buildAsList(i * PAGE_SIZE, (i + 1) * PAGE_SIZE > scenario.getTargets() + ? (scenario.getTargets() - (i * PAGE_SIZE)) : PAGE_SIZE)); + } + + LOGGER.info("Creating {} targets -> Done", scenario.getTargets()); + } + + private static int parseSize(final String s) { + final String size = s.toUpperCase(); + if (size.endsWith("KB")) { + return Integer.valueOf(size.substring(0, size.length() - 2)) * 1024; + } + if (size.endsWith("MB")) { + return Integer.valueOf(size.substring(0, size.length() - 2)) * 1024 * 1024; + } + return Integer.valueOf(size); + } +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/CreateStartedRolloutExample.java b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/CreateStartedRolloutExample.java similarity index 67% rename from examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/CreateStartedRolloutExample.java rename to examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/CreateStartedRolloutExample.java index cd74c0474..b450bbde2 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/CreateStartedRolloutExample.java +++ b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/CreateStartedRolloutExample.java @@ -10,12 +10,12 @@ package org.eclipse.hawkbit.mgmt.client.scenarios; import java.util.List; -import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetResourceClient; -import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetTypeResourceClient; -import org.eclipse.hawkbit.mgmt.client.resource.RolloutResourceClient; -import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleResourceClient; -import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleTypeResourceClient; -import org.eclipse.hawkbit.mgmt.client.resource.TargetResourceClient; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtDistributionSetClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtDistributionSetTypeClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtRolloutClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtSoftwareModuleClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtSoftwareModuleTypeClientResource; +import org.eclipse.hawkbit.mgmt.client.resource.MgmtTargetClientResource; import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetBuilder; import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetTypeBuilder; import org.eclipse.hawkbit.mgmt.client.resource.builder.RolloutBuilder; @@ -23,43 +23,43 @@ import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleAssigmentB import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleBuilder; import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleTypeBuilder; import org.eclipse.hawkbit.mgmt.client.resource.builder.TargetBuilder; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutResponseBody; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRest; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRest; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import org.springframework.beans.factory.annotation.Qualifier; /** * Example for creating and starting a Rollout. * */ -@Component public class CreateStartedRolloutExample { /* known software module type name and key */ - private static final String SM_MODULE_TYPE = "firmware"; + private static final String SM_MODULE_TYPE = "gettingstarted-rollout-example"; /* known distribution set type name and key */ private static final String DS_MODULE_TYPE = SM_MODULE_TYPE; @Autowired - private DistributionSetResourceClient distributionSetResource; + private MgmtDistributionSetClientResource distributionSetResource; @Autowired - private SoftwareModuleResourceClient softwareModuleResource; + @Qualifier("mgmtSoftwareModuleClientResource") + private MgmtSoftwareModuleClientResource softwareModuleResource; @Autowired - private TargetResourceClient targetResource; + private MgmtTargetClientResource targetResource; @Autowired - private RolloutResourceClient rolloutResource; + private MgmtRolloutClientResource rolloutResource; @Autowired - private DistributionSetTypeResourceClient distributionSetTypeResource; + private MgmtDistributionSetTypeClientResource distributionSetTypeResource; @Autowired - private SoftwareModuleTypeResourceClient softwareModuleTypeResource; + private MgmtSoftwareModuleTypeClientResource softwareModuleTypeResource; /** * Run the Rollout scenario. @@ -67,7 +67,7 @@ public class CreateStartedRolloutExample { public void run() { // create three SoftwareModuleTypes - final List createdSoftwareModuleTypes = softwareModuleTypeResource + final List createdSoftwareModuleTypes = softwareModuleTypeResource .createSoftwareModuleTypes(new SoftwareModuleTypeBuilder().key(SM_MODULE_TYPE).name(SM_MODULE_TYPE) .maxAssignments(1).build()) .getBody(); @@ -78,12 +78,12 @@ public class CreateStartedRolloutExample { .getBody(); // create one DistributionSet - final List distributionSetsRest = distributionSetResource.createDistributionSets( + final List distributionSetsRest = distributionSetResource.createDistributionSets( new DistributionSetBuilder().name("rollout-example").version("1.0.0").type(DS_MODULE_TYPE).build()) .getBody(); // create three SoftwareModules - final List softwareModulesRest = softwareModuleResource + final List softwareModulesRest = softwareModuleResource .createSoftwareModules( new SoftwareModuleBuilder().name("firmware").version("1.0.0").type(SM_MODULE_TYPE).build()) .getBody(); @@ -97,7 +97,7 @@ public class CreateStartedRolloutExample { .description("Targets used for rollout example").buildAsList(10)); // create a Rollout - final RolloutResponseBody rolloutResponseBody = rolloutResource + final MgmtRolloutResponseBody rolloutResponseBody = rolloutResource .create(new RolloutBuilder().name("MyRollout").groupSize(2).targetFilterQuery("name==00-FF-AA-0*") .distributionSetId(distributionSetsRest.get(0).getDsId()).successThreshold("80") .errorThreshold("50").build()) diff --git a/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/upload/ArtifactFile.java b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/upload/ArtifactFile.java new file mode 100644 index 000000000..379455580 --- /dev/null +++ b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/upload/ArtifactFile.java @@ -0,0 +1,108 @@ +/** + * 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.mgmt.client.scenarios.upload; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; + +import org.springframework.util.Assert; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; + +/** + * Implementation for {@link MultipartFile} for hawkBit artifact upload. + * + */ +public class ArtifactFile implements MultipartFile { + + private final String name; + + private final String originalFilename; + + private final String contentType; + + private final byte[] content; + + /** + * Create a new ArtifactFile with the given content. + * + * @param name + * the name of the file + * @param content + * the content of the file + */ + public ArtifactFile(final String name, final byte[] content) { + this(name, "", null, content); + } + + /** + * Create a new ArtifactFile with the given content. + * + * @param name + * of the file + * @param originalFilename + * the original filename (as on the client's machine) + * @param contentType + * the content type + * @param content + * of the file + */ + public ArtifactFile(final String name, final String originalFilename, final String contentType, + final byte[] content) { + Assert.hasLength(name, "Name must not be null"); + this.name = name; + this.originalFilename = Optional.ofNullable(originalFilename).orElse(""); + this.contentType = contentType; + this.content = Optional.ofNullable(content).orElse(new byte[0]); + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getOriginalFilename() { + return this.originalFilename; + } + + @Override + public String getContentType() { + return this.contentType; + } + + @Override + public boolean isEmpty() { + return this.content.length == 0; + } + + @Override + public long getSize() { + return this.content.length; + } + + @Override + public byte[] getBytes() throws IOException { + return this.content; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(this.content); + } + + @Override + public void transferTo(final File dest) throws IOException { + FileCopyUtils.copy(this.content, dest); + } + +} diff --git a/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/upload/FeignMultipartEncoder.java b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/upload/FeignMultipartEncoder.java new file mode 100644 index 000000000..5d1e43e96 --- /dev/null +++ b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/upload/FeignMultipartEncoder.java @@ -0,0 +1,155 @@ +/** + * 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.mgmt.client.scenarios.upload; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Type; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Map.Entry; + +import org.springframework.core.io.InputStreamResource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.multipart.MultipartFile; + +import feign.RequestTemplate; +import feign.codec.EncodeException; +import feign.codec.Encoder; + +/** + * A feign encoder implementation which handles {@link MultipartFile} body. + */ +public class FeignMultipartEncoder implements Encoder { + + private final List> converters = new RestTemplate().getMessageConverters(); + private final HttpHeaders multipartHeaders = new HttpHeaders(); + private final HttpHeaders jsonHeaders = new HttpHeaders(); + + private static final Charset UTF_8 = Charset.forName("UTF-8"); + + public FeignMultipartEncoder() { + multipartHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); + jsonHeaders.setContentType(MediaType.APPLICATION_JSON); + } + + @Override + public void encode(final Object object, final Type bodyType, final RequestTemplate template) { + encodeMultipartFormRequest(object, template); + } + + private void encodeMultipartFormRequest(final Object value, final RequestTemplate template) { + if (value == null) { + throw new EncodeException("Cannot encode request with null value."); + } + if (!isMultipartFile(value)) { + throw new EncodeException("Only multipart can be handled by this encoder"); + } + encodeRequest(encodeMultipartFile((MultipartFile) value), multipartHeaders, template); + } + + @SuppressWarnings("unchecked") + private void encodeRequest(final Object value, final HttpHeaders requestHeaders, final RequestTemplate template) { + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + final HttpOutputMessage dummyRequest = new HttpOutputMessageImpl(outputStream, requestHeaders); + try { + final Class requestType = value.getClass(); + final MediaType requestContentType = requestHeaders.getContentType(); + for (final HttpMessageConverter messageConverter : converters) { + if (messageConverter.canWrite(requestType, requestContentType)) { + ((HttpMessageConverter) messageConverter).write(value, requestContentType, dummyRequest); + break; + } + } + } catch (final IOException ex) { + throw new EncodeException("Cannot encode request.", ex); + } + final HttpHeaders headers = dummyRequest.getHeaders(); + if (headers != null) { + for (final Entry> entry : headers.entrySet()) { + template.header(entry.getKey(), entry.getValue()); + } + } + /* + * we should use a template output stream... this will cause issues if + * files are too big, since the whole request will be in memory. + */ + template.body(outputStream.toByteArray(), UTF_8); + } + + private MultiValueMap encodeMultipartFile(final MultipartFile file) { + try { + final MultiValueMap multiValueMap = new LinkedMultiValueMap<>(); + multiValueMap.add("file", new MultipartFileResource(file.getName(), file.getSize(), file.getInputStream())); + return multiValueMap; + } catch (final IOException ex) { + throw new EncodeException("Cannot encode request.", ex); + } + } + + private static boolean isMultipartFile(final Object object) { + return object instanceof MultipartFile; + } + + private static final class HttpOutputMessageImpl implements HttpOutputMessage { + + private final OutputStream body; + private final HttpHeaders headers; + + private HttpOutputMessageImpl(final OutputStream body, final HttpHeaders headers) { + this.body = body; + this.headers = headers; + } + + @Override + public OutputStream getBody() throws IOException { + return body; + } + + @Override + public HttpHeaders getHeaders() { + return headers; + } + + } + + /** + * Dummy resource class. Wraps file content and its original name. + */ + static class MultipartFileResource extends InputStreamResource { + + private final String filename; + private final long size; + + public MultipartFileResource(final String filename, final long size, final InputStream inputStream) { + super(inputStream); + this.size = size; + this.filename = filename; + } + + @Override + public String getFilename() { + return this.filename; + } + + @Override + public long contentLength() throws IOException { + return size; + } + + } +} diff --git a/examples/hawkbit-example-mgmt-simulator/src/main/resources/application.properties b/examples/hawkbit-example-mgmt-simulator/src/main/resources/application.properties new file mode 100644 index 000000000..747e8ffe9 --- /dev/null +++ b/examples/hawkbit-example-mgmt-simulator/src/main/resources/application.properties @@ -0,0 +1,22 @@ +# +# 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 +# + +hawkbit.url=http://localhost:8080 +hawkbit.username=admin +hawkbit.password=admin + +spring.main.show-banner=false + +hawkbit.scenarios.[0].cleanRepository=false +hawkbit.scenarios.[0].targets=0 +hawkbit.scenarios.[0].ds-name=gettingstarted-example +hawkbit.scenarios.[0].distribution-sets=3 +hawkbit.scenarios.[0].sm-fw-name=gettingstarted-example +hawkbit.scenarios.[0].sm-sw-name=gettingstarted-example +hawkbit.scenarios.[0].runRollouts=false \ No newline at end of file diff --git a/examples/hawkbit-mgmt-api-client/src/main/resources/logback.xml b/examples/hawkbit-example-mgmt-simulator/src/main/resources/logback.xml similarity index 57% rename from examples/hawkbit-mgmt-api-client/src/main/resources/logback.xml rename to examples/hawkbit-example-mgmt-simulator/src/main/resources/logback.xml index 0174611e6..768f30687 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/resources/logback.xml +++ b/examples/hawkbit-example-mgmt-simulator/src/main/resources/logback.xml @@ -10,17 +10,11 @@ --> - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - + - + - + diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/Application.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/Application.java deleted file mode 100644 index 27584b50a..000000000 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/Application.java +++ /dev/null @@ -1,77 +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.mgmt.client; - -import org.eclipse.hawkbit.mgmt.client.scenarios.CreateStartedRolloutExample; -import org.eclipse.hawkbit.mgmt.client.scenarios.GettingStartedDefaultScenario; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.netflix.feign.EnableFeignClients; -import org.springframework.context.annotation.Bean; - -import feign.Contract; -import feign.auth.BasicAuthRequestInterceptor; - -@SpringBootApplication -@EnableFeignClients -@EnableConfigurationProperties(ClientConfigurationProperties.class) -public class Application implements CommandLineRunner { - - @Autowired - private ClientConfigurationProperties configuration; - - @Autowired - private GettingStartedDefaultScenario gettingStarted; - - @Autowired - private CreateStartedRolloutExample gettingStartedRolloutScenario; - - public static void main(final String[] args) { - new SpringApplicationBuilder().showBanner(false).sources(Application.class).run(args); - } - - @Override - public void run(final String... args) throws Exception { - if (containsArg("--createrollout", args)) { - // run the create and start rollout example - gettingStartedRolloutScenario.run(); - } else { - // run the getting started scenario which creates a setup of - // distribution set and software modules to be used - gettingStarted.run(); - } - } - - @Bean - public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { - return new BasicAuthRequestInterceptor(configuration.getUsername(), configuration.getPassword()); - } - - @Bean - public ApplicationJsonRequestHeaderInterceptor jsonHeaderInterceptor() { - return new ApplicationJsonRequestHeaderInterceptor(); - } - - @Bean - public Contract feignContract() { - return new IgnoreMultipleConsumersProducersSpringMvcContract(); - } - - private boolean containsArg(final String containsArg, final String... args) { - for (final String arg : args) { - if (arg.equalsIgnoreCase(containsArg)) { - return true; - } - } - return false; - } -} \ No newline at end of file diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java deleted file mode 100644 index 68f35b550..000000000 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java +++ /dev/null @@ -1,60 +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.mgmt.client; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -/** - * Configuration bean which holds the configuration of the client e.g. the base - * URL of the hawkbit-server and the credentials to use the RESTful Management - * API. - */ -@ConfigurationProperties(prefix = "hawkbit") -public class ClientConfigurationProperties { - - /** - * Update server URI. - */ - private String url = "localhost:8080"; - - /** - * Update server user name. - */ - private String username = "admin"; - - /** - * Update server password. - */ - private String password = "admin"; // NOSONAR this password is only used for - // examples - - public String getUrl() { - return url; - } - - public void setUrl(final String url) { - this.url = url; - } - - public String getUsername() { - return username; - } - - public void setUsername(final String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(final String password) { - this.password = password; - } -} 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 deleted file mode 100644 index 01acdac72..000000000 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetBuilder.java +++ /dev/null @@ -1,96 +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.mgmt.client.resource.builder; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPost; - -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; - - /** - * @param name - * the name of the distribution set - * @return the builder itself - */ - public DistributionSetBuilder name(final String name) { - this.name = name; - return this; - } - - /** - * @param version - * the version of the distribution set - * @return the builder itself - */ - public DistributionSetBuilder version(final String version) { - this.version = version; - return this; - } - - /** - * @param type - * the distribution set type name for this distribution set - * @return the builder itself - */ - public DistributionSetBuilder type(final String type) { - this.type = type; - return this; - } - - /** - * Builds a list with a single entry of - * {@link DistributionSetRequestBodyPost} which can directly be used to post - * on the RESTful-API. - * - * @return a single entry list of {@link DistributionSetRequestBodyPost} - */ - public List build() { - return Lists.newArrayList(doBuild(name)); - } - - /** - * Builds a list of multiple {@link DistributionSetRequestBodyPost} to - * create multiple distribution sets at once. An increasing number will be - * added to the name of the distribution set. The version and type will - * remain the same. - * - * @param count - * the amount of distribution sets body which should be created - * @return a list of {@link DistributionSetRequestBodyPost} - */ - public List buildAsList(final int count) { - final ArrayList bodyList = Lists.newArrayList(); - for (int index = 0; index < count; index++) { - bodyList.add(doBuild(name + index)); - } - - return bodyList; - } - - private DistributionSetRequestBodyPost doBuild(final String prefixName) { - final DistributionSetRequestBodyPost body = new DistributionSetRequestBodyPost(); - body.setName(prefixName); - body.setVersion(version); - body.setType(type); - return body; - } - -} 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 deleted file mode 100644 index 169a159d0..000000000 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleBuilder.java +++ /dev/null @@ -1,101 +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.mgmt.client.resource.builder; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRequestBodyPost; - -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; - private String version; - private String type; - - /** - * @param name - * the name of the software module - * @return the builder itself - */ - public SoftwareModuleBuilder name(final String name) { - this.name = name; - return this; - } - - /** - * @param version - * the version of the software module - * @return the builder itsefl - */ - public SoftwareModuleBuilder version(final String version) { - this.version = version; - return this; - } - - /** - * @param type - * the key of the software module type to be used for this - * software module - * @return the builder itself - */ - public SoftwareModuleBuilder type(final String type) { - this.type = type; - return this; - } - - /** - * Builds a list with a single entry of - * {@link SoftwareModuleRequestBodyPost} which can directly be used in the - * RESTful-API. - * - * @return a single entry list of {@link SoftwareModuleRequestBodyPost} - */ - public List build() { - return Lists.newArrayList(doBuild(name)); - } - - /** - * Builds a list of multiple {@link SoftwareModuleRequestBodyPost} to create - * multiple software module at once. An increasing number will be added to - * the name of the software module. The version and type will remain the - * same. - * - * @param count - * the amount of software module body which should be created - * @return a list of {@link DistributionSetTypeRequestBodyPost} - */ - public List buildAsList(final int count) { - final ArrayList bodyList = Lists.newArrayList(); - for (int index = 0; index < count; index++) { - bodyList.add(doBuild(name + index)); - } - - return bodyList; - } - - private SoftwareModuleRequestBodyPost doBuild(final String prefixName) { - final SoftwareModuleRequestBodyPost body = new SoftwareModuleRequestBodyPost(); - body.setName(prefixName); - body.setVersion(version); - body.setType(type); - return body; - } - -} 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 deleted file mode 100644 index aba1188dc..000000000 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java +++ /dev/null @@ -1,98 +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.mgmt.client.resource.builder; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody; - -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; - private String name; - private String description; - - /** - * @param controllerId - * the ID of the controller/target - * @return the builder itself - */ - public TargetBuilder controllerId(final String controllerId) { - this.controllerId = controllerId; - return this; - } - - /** - * @param name - * the name of the target - * @return the builder itself - */ - public TargetBuilder name(final String name) { - this.name = name; - return this; - } - - /** - * @param description - * the description of the target - * @return the builder itself - */ - public TargetBuilder description(final String description) { - this.description = description; - return this; - } - - /** - * Builds a list with a single entry of {@link TargetRequestBody} which can - * directly be used in the RESTful-API. - * - * @return a single entry list of {@link TargetRequestBody} - */ - public List build() { - return Lists.newArrayList(doBuild(controllerId)); - } - - /** - * Builds a list of multiple {@link TargetRequestBody} to create multiple - * targets at once. An increasing number will be added to the controllerId - * of the target. The name and description will remain. - * - * @param count - * the amount of software module type bodies which should be - * created - * @return a list of {@link SoftwareModuleTypeRequestBodyPost} - */ - public List buildAsList(final int count) { - final ArrayList bodyList = Lists.newArrayList(); - for (int index = 0; index < count; index++) { - bodyList.add(doBuild(controllerId + index)); - } - return bodyList; - } - - private TargetRequestBody doBuild(final String prefixControllerId) { - final TargetRequestBody body = new TargetRequestBody(); - body.setControllerId(prefixControllerId); - body.setName(name); - body.setDescription(description); - return body; - } - -} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/GettingStartedDefaultScenario.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/GettingStartedDefaultScenario.java deleted file mode 100644 index 5873403f0..000000000 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/GettingStartedDefaultScenario.java +++ /dev/null @@ -1,137 +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.mgmt.client.scenarios; - -import java.util.List; - -import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetResourceClient; -import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetTypeResourceClient; -import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleResourceClient; -import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleTypeResourceClient; -import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetBuilder; -import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetTypeBuilder; -import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleAssigmentBuilder; -import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleBuilder; -import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleTypeBuilder; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRest; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -/** - * - * Default getting started scenario. - * - */ -@Component -public class GettingStartedDefaultScenario { - - private static final Logger LOGGER = LoggerFactory.getLogger(GettingStartedDefaultScenario.class); - - /* known software module type name and key */ - private static final String SM_MODULE_TYPE = "gettingstarted"; - - /* known distribution set type name and key */ - private static final String DS_MODULE_TYPE = SM_MODULE_TYPE; - - /* known distribution name of this getting started example */ - private static final String SM_EXAMPLE_NAME = "gettingstarted-example"; - - /* known distribution name of this getting started example */ - private static final String DS_EXAMPLE_NAME = SM_EXAMPLE_NAME; - - @Autowired - private DistributionSetResourceClient distributionSetResource; - - @Autowired - private DistributionSetTypeResourceClient distributionSetTypeResource; - - @Autowired - private SoftwareModuleResourceClient softwareModuleResource; - - @Autowired - private SoftwareModuleTypeResourceClient softwareModuleTypeResource; - - /** - * Run the default getting started scenario. - */ - public void run() { - - LOGGER.info("Running Getting-Started-Scenario..."); - - // create one SoftwareModuleTypes - LOGGER.info("Creating software module type {}", SM_MODULE_TYPE); - final List createdSoftwareModuleTypes = softwareModuleTypeResource - .createSoftwareModuleTypes(new SoftwareModuleTypeBuilder().key(SM_MODULE_TYPE).name(SM_MODULE_TYPE) - .maxAssignments(1).build()) - .getBody(); - - // create one DistributionSetType - LOGGER.info("Creating distribution set type {}", DS_MODULE_TYPE); - distributionSetTypeResource.createDistributionSetTypes(new DistributionSetTypeBuilder().key(DS_MODULE_TYPE) - .name(DS_MODULE_TYPE).mandatorymodules(createdSoftwareModuleTypes.get(0).getModuleId()).build()); - - // create three DistributionSet - final String dsVersion1 = "1.0.0"; - final String dsVersion2 = "2.0.0"; - final String dsVersion3 = "2.1.0"; - - LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion1); - final List distributionSetsRest1 = distributionSetResource.createDistributionSets( - new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion1).type(DS_MODULE_TYPE).build()) - .getBody(); - - LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion2); - final List distributionSetsRest2 = distributionSetResource.createDistributionSets( - new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion2).type(DS_MODULE_TYPE).build()) - .getBody(); - - LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion3); - final List distributionSetsRest3 = distributionSetResource.createDistributionSets( - new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion3).type(DS_MODULE_TYPE).build()) - .getBody(); - - // create three SoftwareModules - final String swVersion1 = "1"; - final String swVersion2 = "2"; - final String swVersion3 = "3"; - - LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion1); - final List softwareModulesRest1 = softwareModuleResource.createSoftwareModules( - new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion1).type(SM_MODULE_TYPE).build()) - .getBody(); - LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion2); - final List softwareModulesRest2 = softwareModuleResource.createSoftwareModules( - new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion2).type(SM_MODULE_TYPE).build()) - .getBody(); - LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion3); - final List softwareModulesRest3 = softwareModuleResource.createSoftwareModules( - new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion3).type(SM_MODULE_TYPE).build()) - .getBody(); - - // Assign SoftwareModules to DistributionSet - LOGGER.info("Assign software module {}:{} to distribution set {}:{}", SM_EXAMPLE_NAME, swVersion1, - DS_EXAMPLE_NAME, dsVersion1); - distributionSetResource.assignSoftwareModules(distributionSetsRest1.get(0).getDsId(), - new SoftwareModuleAssigmentBuilder().id(softwareModulesRest1.get(0).getModuleId()).build()); - - LOGGER.info("Assign software module {}:{} to distribution set {}:{}", SM_EXAMPLE_NAME, swVersion2, - DS_EXAMPLE_NAME, dsVersion2); - distributionSetResource.assignSoftwareModules(distributionSetsRest2.get(0).getDsId(), - new SoftwareModuleAssigmentBuilder().id(softwareModulesRest2.get(0).getModuleId()).build()); - - LOGGER.info("Assign software module {}:{} to distribution set {}:{}", SM_EXAMPLE_NAME, swVersion3, - DS_EXAMPLE_NAME, dsVersion3); - distributionSetResource.assignSoftwareModules(distributionSetsRest3.get(0).getDsId(), - new SoftwareModuleAssigmentBuilder().id(softwareModulesRest3.get(0).getModuleId()).build()); - } -} diff --git a/examples/hawkbit-mgmt-api-client/src/main/resources/application.properties b/examples/hawkbit-mgmt-api-client/src/main/resources/application.properties deleted file mode 100644 index d3a3eb969..000000000 --- a/examples/hawkbit-mgmt-api-client/src/main/resources/application.properties +++ /dev/null @@ -1,14 +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 -# - -hawkbit.url=localhost:8080 -hawkbit.username=admin -hawkbit.password=admin - -spring.main.show-banner=false \ No newline at end of file diff --git a/examples/pom.xml b/examples/pom.xml index 5f1377123..fb8ef3fc3 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -8,8 +8,7 @@ http://www.eclipse.org/legal/epl-v10.html --> - + 4.0.0 @@ -19,13 +18,45 @@ hawkbit-examples-parent - hawkBit :: Examples Parent + hawkBit-example :: Parent pom hawkbit-device-simulator hawkbit-example-app - hawkbit-mgmt-api-client - + hawkbit-example-core-feign-client + hawkbit-example-ddi-feign-client + hawkbit-example-mgmt-feign-client + hawkbit-example-mgmt-simulator + + + + + 8.14.2 + + + + + + com.netflix.feign + feign-core + + + ${feign.version} + + + com.netflix.feign + feign-jackson + + + ${feign.version} + + + com.netflix.feign + feign-slf4j + ${feign.version} + + + \ No newline at end of file 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 5f12498ff..eabd2b329 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 @@ -87,9 +87,7 @@ public class ArtifactStore implements ArtifactRepository { /** * Retrieves a {@link GridFSDBFile} from the store by it's MD5 hash. - * - * @param tenant - * the tenant to retrieve the artifacts from, ignore case. + * * @param md5Hash * the md5-hash of the file to lookup. * @return The gridfs file object or {@code null} if no file exists. @@ -100,9 +98,7 @@ public class ArtifactStore implements ArtifactRepository { /** * Retrieves a {@link GridFSDBFile} from the store by it's object id. - * - * @param tenant - * the tenant to retrieve the artifacts from, ignore case. + * * @param id * the id of the file to lookup. * @return The gridfs file object or {@code null} if no file exists. @@ -124,11 +120,9 @@ public class ArtifactStore implements ArtifactRepository { try { LOGGER.debug("storing file {} of content {}", filename, contentType); tempFile = File.createTempFile("uploadFile", null); - try (final FileOutputStream os = new FileOutputStream(tempFile)) { - try (BufferedOutputStream bos = new BufferedOutputStream(os)) { - try (BufferedInputStream bis = new BufferedInputStream(content)) { - return store(content, contentType, bos, tempFile, hash); - } + try (final BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tempFile))) { + try (BufferedInputStream bis = new BufferedInputStream(content)) { + return store(bis, contentType, bos, tempFile, hash); } } } catch (final IOException | MongoException e1) { @@ -207,6 +201,9 @@ public class ArtifactStore implements ArtifactRepository { throws NoSuchAlgorithmException, IOException { String sha1Hash; // compute digest + // Exception squid:S2070 - not used for hashing sensitive + // data + @SuppressWarnings("squid:S2070") final MessageDigest md = MessageDigest.getInstance("SHA-1"); try (final DigestOutputStream dos = new DigestOutputStream(os, md)) { ByteStreams.copy(stream, dos); @@ -230,15 +227,13 @@ public class ArtifactStore implements ArtifactRepository { * @return a paged list of artifacts mapped from the given dbFiles */ private List map(final List dbFiles) { - return dbFiles.stream().map(dbFile -> map(dbFile)).collect(Collectors.toList()); + return dbFiles.stream().map(this::map).collect(Collectors.toList()); } /** * Retrieves a list of {@link GridFSDBFile} from the store by all SHA1 * hashes. - * - * @param tenant - * the tenant to retrieve the artifacts from, ignore case. + * * @param sha1Hashes * the sha1-hashes of the files to lookup. * @return list of artifacts @@ -251,8 +246,6 @@ public class ArtifactStore implements ArtifactRepository { /** * Retrieves a list of {@link GridFSDBFile} from the store by all ids. * - * @param tenant - * the tenant to retrieve the artifacts from, ignore case. * @param ids * the ids of the files to lookup. * @return list of artfiacts diff --git a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStoreAutoConfiguration.java b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStoreAutoConfiguration.java index 43bcddaf0..8a1cb89a9 100644 --- a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStoreAutoConfiguration.java +++ b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStoreAutoConfiguration.java @@ -10,18 +10,13 @@ package org.eclipse.hawkbit.artifact.repository; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** * Auto configuration for the {@link ArtifactStore}. - * - * - * */ @Configuration -@ComponentScan @ConditionalOnMissingBean(value = ArtifactRepository.class) @Import(value = MongoConfiguration.class) public class ArtifactStoreAutoConfiguration { diff --git a/hawkbit-autoconfigure/pom.xml b/hawkbit-autoconfigure/pom.xml index 7670da406..044e6aece 100644 --- a/hawkbit-autoconfigure/pom.xml +++ b/hawkbit-autoconfigure/pom.xml @@ -46,7 +46,7 @@ org.eclipse.hawkbit - hawkbit-repository + hawkbit-repository-jpa ${project.version} true @@ -64,7 +64,13 @@ org.eclipse.hawkbit - hawkbit-rest-resource + hawkbit-ddi-resource + ${project.version} + true + + + org.eclipse.hawkbit + hawkbit-mgmt-resource ${project.version} true diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/CacheAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/CacheAutoConfiguration.java index 6696c44ca..a170dfcd3 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/CacheAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/CacheAutoConfiguration.java @@ -25,6 +25,7 @@ import org.springframework.cache.interceptor.CacheOperationInvocationContext; import org.springframework.cache.interceptor.SimpleCacheResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; /** * A configuration for configuring the spring {@link CacheManager} for specific @@ -33,9 +34,6 @@ import org.springframework.context.annotation.Configuration; * * This is done by providing a special {@link TenantCacheResolver} which * generates a cache name included the current tenant. - * - * - * */ @Configuration @EnableCaching @@ -51,18 +49,27 @@ public class CacheAutoConfiguration extends CachingConfigurerSupport { @Override @Bean @ConditionalOnMissingBean + @Primary public TenancyCacheManager cacheManager() { - return new TenantAwareCacheManager(new GuavaCacheManager(), tenantAware); + return new TenantAwareCacheManager(directCacheManager(), tenantAware); + } + + /** + * @return the direct cache manager to access without tenant aware check, + * cause in sometimes it's necessary to access the cache directly + * without having the current tenant, e.g. initial creation of + * tenant + */ + @Bean(name = "directCacheManager") + @ConditionalOnMissingBean(name = "directCacheManager") + public CacheManager directCacheManager() { + return new GuavaCacheManager(); } /** * A {@link SimpleCacheResolver} implementation which includes the * {@link TenantAware#getCurrentTenant()} into the cache name before * resolving it. - * - * - * - * */ public class TenantCacheResolver extends SimpleCacheResolver { diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/DownloadIdCacheAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/DownloadIdCacheAutoConfiguration.java index 495200dec..134b50d90 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/DownloadIdCacheAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/DownloadIdCacheAutoConfiguration.java @@ -31,7 +31,7 @@ public class DownloadIdCacheAutoConfiguration { private CacheManager cacheManager; /** - * Bean for the downlod id cache. + * Bean for the download id cache. * * @return the cache */ diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/eventbus/EventBusAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/eventbus/EventBusAutoConfiguration.java index 37e72880c..d4cc32825 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/eventbus/EventBusAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/eventbus/EventBusAutoConfiguration.java @@ -12,7 +12,7 @@ import java.util.concurrent.Executor; import org.eclipse.hawkbit.eventbus.EventBusSubscriberProcessor; import org.eclipse.hawkbit.eventbus.EventSubscriber; -import org.eclipse.hawkbit.repository.model.helper.EventBusHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java new file mode 100644 index 000000000..dd6ead86b --- /dev/null +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java @@ -0,0 +1,25 @@ +/** + * 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.autoconfigure.repository; + +import org.eclipse.hawkbit.EnableJpaRepository; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * Auto-Configuration for enabling the REST-Resources. + * + */ +@Configuration +@ConditionalOnClass({ EnableJpaRepository.class }) +@Import({ EnableJpaRepository.class }) +public class JpaRepositoryAutoConfiguration { + +} diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerAutoConfiguration.java index cdbbcba5b..7e2b780b4 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerAutoConfiguration.java @@ -23,7 +23,6 @@ import org.springframework.scheduling.annotation.EnableAsync; * * */ - @Configuration @EnableAsync @ConditionalOnMissingBean(AsyncConfigurer.class) diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java index 35996a114..d6f3ca430 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java @@ -20,7 +20,7 @@ public class AsyncConfigurerThreadpoolProperties { /** * Max queue size for central event executor. */ - private Integer queuesize = 250; + private Integer queuesize = 5_000; /** * Core processing threads for central event executor. @@ -30,7 +30,12 @@ public class AsyncConfigurerThreadpoolProperties { /** * Maximum thread pool size for central event executor. */ - private Integer maxthreads = 50; + private Integer maxthreads = 20; + + /** + * Core processing threads for scheduled event executor. + */ + private Integer schedulerThreads = 3; /** * When the number of threads is greater than the core, this is the maximum @@ -70,4 +75,12 @@ public class AsyncConfigurerThreadpoolProperties { this.idletimeout = idletimeout; } + public Integer getSchedulerThreads() { + return schedulerThreads; + } + + public void setSchedulerThreads(final Integer schedulerThreads) { + this.schedulerThreads = schedulerThreads; + } + } diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java index 43a096e7d..917e4e4ef 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java @@ -11,7 +11,11 @@ package org.eclipse.hawkbit.autoconfigure.scheduling; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; @@ -21,7 +25,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; +import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; import org.springframework.security.concurrent.DelegatingSecurityContextExecutor; +import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService; +import org.springframework.security.concurrent.DelegatingSecurityContextScheduledExecutorService; import com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -39,21 +49,46 @@ public class ExecutorAutoConfiguration { private AsyncConfigurerThreadpoolProperties asyncConfigurerProperties; /** - * @return ExecutorService for general purpose multi threaded operations + * @return ExecutorService with security context availability in thread + * execution. + */ + @Bean(destroyMethod = "shutdown") + @ConditionalOnMissingBean + public ExecutorService asyncExecutor() { + return new DelegatingSecurityContextExecutorService(threadPoolExecutor()); + } + + /** + * @return {@link TaskExecutor} for task execution */ @Bean @ConditionalOnMissingBean - public Executor asyncExecutor() { + public TaskExecutor taskExecutor() { + return new ConcurrentTaskExecutor(asyncExecutor()); + } + + /** + * @return central ThreadPoolExecutor for general purpose multi threaded + * operations. Tries an orderly shutdown when destroyed. + */ + private ThreadPoolExecutor threadPoolExecutor() { final BlockingQueue blockingQueue = new ArrayBlockingQueue<>( asyncConfigurerProperties.getQueuesize()); - final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(asyncConfigurerProperties.getCorethreads(), + return new ThreadPoolExecutor(asyncConfigurerProperties.getCorethreads(), asyncConfigurerProperties.getMaxthreads(), asyncConfigurerProperties.getIdletimeout(), TimeUnit.MILLISECONDS, blockingQueue, - new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build()); - threadPoolExecutor.setRejectedExecutionHandler((r, executor) -> LOGGER.warn( - "Reject runnable for centralExecutorService, reached limit of queue size {}", - executor.getQueue().size())); - return new DelegatingSecurityContextExecutor(threadPoolExecutor); + new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build(), + new PoolSizeExceededPolicy()); + } + + private static class PoolSizeExceededPolicy extends CallerRunsPolicy { + @Override + public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) { + LOGGER.warn( + "Caller has to run on its own instead of centralExecutorService, reached limit of queue size {}", + executor.getQueue().size()); + super.rejectedExecution(r, executor); + } } /** @@ -69,4 +104,25 @@ public class ExecutorAutoConfiguration { return new DelegatingSecurityContextExecutor(threadPoolExecutor); } + /** + * @return {@link ScheduledExecutorService} with security context + * availability in thread execution. + */ + @Bean(destroyMethod = "shutdown") + @ConditionalOnMissingBean + public ScheduledExecutorService scheduledExecutorService() { + return new DelegatingSecurityContextScheduledExecutorService( + Executors.newScheduledThreadPool(asyncConfigurerProperties.getSchedulerThreads(), + new ThreadFactoryBuilder().setNameFormat("central-scheduled-executor-pool-%d").build())); + } + + /** + * @return {@link TaskScheduler} for task execution + */ + @Bean + @ConditionalOnMissingBean + public TaskScheduler taskScheduler() { + return new ConcurrentTaskScheduler(scheduledExecutorService()); + } + } diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementConfiguration.java new file mode 100644 index 000000000..fc979fd67 --- /dev/null +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementConfiguration.java @@ -0,0 +1,76 @@ +/** + * 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.autoconfigure.security; + +import java.util.ArrayList; + +import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator; +import org.eclipse.hawkbit.im.authentication.PermissionUtils; +import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +/** + * Auto-configuration for the in-memory-user-management. + * + */ +@Configuration +@ConditionalOnMissingBean(UserDetailsService.class) +public class InMemoryUserManagementConfiguration extends GlobalAuthenticationConfigurerAdapter { + + @Override + public void configure(final AuthenticationManagerBuilder auth) throws Exception { + final DaoAuthenticationProvider userDaoAuthenticationProvider = new TenantDaoAuthenticationProvider(); + userDaoAuthenticationProvider.setUserDetailsService(userDetailsService()); + auth.authenticationProvider(userDaoAuthenticationProvider); + } + + /** + * @return the user details service to load a user from memory user manager. + */ + @Bean + @ConditionalOnMissingBean + public UserDetailsService userDetailsService() { + final InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(new ArrayList<>()); + inMemoryUserDetailsManager.setAuthenticationManager(null); + inMemoryUserDetailsManager.createUser(new User("admin", "admin", PermissionUtils.createAllAuthorityList())); + return inMemoryUserDetailsManager; + } + + /** + * @return the multi-tenancy indicator to disallow multi-tenancy + */ + @Bean + @ConditionalOnMissingBean + public MultitenancyIndicator multiTenancyIndicator() { + return () -> false; + } + + private static class TenantDaoAuthenticationProvider extends DaoAuthenticationProvider { + + @Override + protected Authentication createSuccessAuthentication(final Object principal, + final Authentication authentication, final UserDetails user) { + final UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal, + authentication.getCredentials(), user.getAuthorities()); + result.setDetails(new TenantAwareAuthenticationDetails("DEFAULT", false)); + return result; + } + } +} diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java index 8a3a50ad2..d74b27dc8 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java @@ -8,43 +8,17 @@ */ package org.eclipse.hawkbit.autoconfigure.security; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator; import org.eclipse.hawkbit.im.authentication.PermissionService; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; -import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter; -import org.eclipse.hawkbit.security.SecurityContextTenantAware; import org.eclipse.hawkbit.security.DdiSecurityProperties; +import org.eclipse.hawkbit.security.SecurityContextTenantAware; import org.eclipse.hawkbit.security.SpringSecurityAuditorAware; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.AuditorAware; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.authentication.dao.DaoAuthenticationProvider; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; /** * {@link EnableAutoConfiguration Auto-configuration} for security. @@ -88,119 +62,4 @@ public class SecurityAutoConfiguration { return new SpringSecurityAuditorAware(); } - /** - * Auto-configuration for the in-memory-user-management. - * - * - * - */ - @Configuration - @ConditionalOnMissingBean(value = { UserAuthenticationFilter.class }) - public static class InMemoryUserManagementConfiguration extends GlobalAuthenticationConfigurerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(InMemoryUserManagementConfiguration.class); - - @Autowired - private AuthenticationConfiguration configuration; - - /* - * (non-Javadoc) - * - * @see org.springframework.security.config.annotation.authentication. - * configurers. GlobalAuthenticationConfigurerAdapter - * #configure(org.springframework.security.config.annotation. - * authentication.builders.AuthenticationManagerBuilder) - */ - @Override - public void configure(final AuthenticationManagerBuilder auth) throws Exception { - final DaoAuthenticationProvider userDaoAuthenticationProvider = new TenantDaoAuthenticationProvider(); - userDaoAuthenticationProvider.setUserDetailsService(userDetailsService()); - auth.authenticationProvider(userDaoAuthenticationProvider); - } - - /** - * @return the user details service to load a user from memory user - * manager. - */ - @Bean - public UserDetailsService userDetailsService() { - final InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager( - new ArrayList<>()); - inMemoryUserDetailsManager.setAuthenticationManager(null); - inMemoryUserDetailsManager.createUser(new User("admin", "admin", getAllAuthorities())); - return inMemoryUserDetailsManager; - } - - /** - * @return the multi-tenancy indicator to disallow multi-tenancy - */ - @Bean - public MultitenancyIndicator multiTenancyIndicator() { - return new MultitenancyIndicator() { - @Override - public boolean isMultiTenancySupported() { - return false; - } - }; - } - - private Collection getAllAuthorities() { - final List allPermissions = new ArrayList<>(); - final Field[] declaredFields = SpPermission.class.getDeclaredFields(); - for (final Field field : declaredFields) { - if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) { - field.setAccessible(true); - try { - final String permissionName = (String) field.get(null); - allPermissions.add(new SimpleGrantedAuthority(permissionName)); - } catch (final IllegalAccessException e) { - LOGGER.error(e.getMessage(), e); - } - } - } - return allPermissions; - } - - private static class TenantDaoAuthenticationProvider extends DaoAuthenticationProvider { - /* - * (non-Javadoc) - * - * @see org.springframework.security.authentication.dao. - * AbstractUserDetailsAuthenticationProvider - * #createSuccessAuthentication(java.lang.Object, - * org.springframework.security.core.Authentication, - * org.springframework.security.core.userdetails.UserDetails) - */ - @Override - protected Authentication createSuccessAuthentication(final Object principal, - final Authentication authentication, final UserDetails user) { - final UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal, - authentication.getCredentials(), user.getAuthorities()); - result.setDetails(new TenantAwareAuthenticationDetails("DEFAULT", false)); - return result; - } - } - - /** - * @return the {@link UserAuthenticationFilter} to include into the SP - * security configuration. - * @throws Exception - * lazy bean exception maybe if the authentication manager - * cannot be instantiated - */ - @Bean - public UserAuthenticationFilter userAuthenticationFilter() throws Exception { - return new UserAuthenticationFilterBasicAuth(configuration.getAuthenticationManager()); - } - - private static final class UserAuthenticationFilterBasicAuth extends BasicAuthenticationFilter - implements UserAuthenticationFilter { - - private UserAuthenticationFilterBasicAuth(final AuthenticationManager authenticationManager) { - super(authenticationManager); - } - - } - } - } diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java index 9638377eb..1e4dbfb27 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java @@ -8,6 +8,10 @@ */ package org.eclipse.hawkbit.autoconfigure.security; +import static com.google.common.collect.Lists.newArrayList; +import static org.springframework.context.annotation.AdviceMode.ASPECTJ; +import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE; + import java.io.IOException; import java.net.URI; @@ -26,10 +30,10 @@ import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.im.authentication.TenantUserPasswordAuthenticationToken; import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.rest.resource.RestConstants; import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource; import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.DosFilter; @@ -46,18 +50,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.context.embedded.FilterRegistrationBean; import org.springframework.boot.context.embedded.ServletListenerRegistrationBean; import org.springframework.cache.Cache; -import org.springframework.context.annotation.AdviceMode; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.WebSecurityConfigurer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -72,10 +77,13 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter; +import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.springframework.security.web.header.writers.frameoptions.StaticAllowFromStrategy; import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter; import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode; import org.springframework.security.web.session.HttpSessionEventPublisher; +import org.springframework.security.web.session.SessionManagementFilter; import org.vaadin.spring.security.VaadinSecurityContext; import org.vaadin.spring.security.annotation.EnableVaadinSecurity; import org.vaadin.spring.security.web.VaadinDefaultRedirectStrategy; @@ -83,30 +91,49 @@ import org.vaadin.spring.security.web.VaadinRedirectStrategy; import org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler; import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSuccessHandler; -import com.google.common.collect.Lists; - /** - * All configurations related to SP authentication and authorization layer. - * - * - * + * All configurations related to HawkBit's authentication and authorization + * layer. */ @Configuration @EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true) +@EnableGlobalMethodSecurity(prePostEnabled = true, mode = ASPECTJ, proxyTargetClass = true, securedEnabled = true) @EnableWebMvcSecurity -@Order(value = Ordered.HIGHEST_PRECEDENCE) +@Order(value = HIGHEST_PRECEDENCE) public class SecurityManagedConfiguration { + private static final Logger LOG = LoggerFactory.getLogger(SecurityManagedConfiguration.class); @Autowired private HawkbitSecurityProperties securityProperties; + @Autowired + private AuthenticationConfiguration configuration; + + /** + * @return the {@link UserAuthenticationFilter} to include into the SP + * security configuration. + * @throws Exception + * lazy bean exception maybe if the authentication manager + * cannot be instantiated + */ + @Bean + @ConditionalOnMissingBean + public UserAuthenticationFilter userAuthenticationFilter() throws Exception { + return new UserAuthenticationFilterBasicAuth(configuration.getAuthenticationManager()); + } + + private static final class UserAuthenticationFilterBasicAuth extends BasicAuthenticationFilter + implements UserAuthenticationFilter { + + private UserAuthenticationFilterBasicAuth(final AuthenticationManager authenticationManager) { + super(authenticationManager); + } + + } + /** * {@link WebSecurityConfigurer} for the internal SP controller API. - * - * - * */ @Configuration @Order(300) @@ -114,19 +141,25 @@ public class SecurityManagedConfiguration { @Autowired private ControllerManagement controllerManagement; + @Autowired private TenantConfigurationManagement tenantConfigurationManagement; + @Autowired private TenantAware tenantAware; + @Autowired private DdiSecurityProperties ddiSecurityConfiguration; + @Autowired private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties; + @Autowired private SystemSecurityContext systemSecurityContext; @Override protected void configure(final HttpSecurity http) throws Exception { + final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource(); final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter( @@ -164,16 +197,19 @@ public class SecurityManagedConfiguration { } if (ddiSecurityConfiguration.getAuthentication().getAnonymous().isEnabled()) { + LOG.info( - "******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************"); + "******************\n** Anonymous controller security enabled, should only be used for developing purposes **\n******************"); + final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter( "controllerAnonymousFilter", "anonymous", - Lists.newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS), + newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS), new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE))); anoymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource); httpSec.requestMatchers().antMatchers("/*/controller/v1/**", "/*/controller/artifacts/v1/**").and() .securityContext().disable().anonymous().authenticationFilter(anoymousFilter); } else { + httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter) .addFilter(gatewaySecurityTokenFilter).addFilter(controllerAnonymousDownloadFilter) .antMatcher("/*/controller/**").anonymous().disable().authorizeRequests().anyRequest() @@ -186,6 +222,7 @@ public class SecurityManagedConfiguration { @Override protected void configure(final AuthenticationManagerBuilder auth) throws Exception { + auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider( ddiSecurityConfiguration.getRp().getTrustedIPs())); } @@ -200,6 +237,7 @@ public class SecurityManagedConfiguration { @Bean @Order(50) public FilterRegistrationBean dosFilter() { + final FilterRegistrationBean filterRegBean = new FilterRegistrationBean(); filterRegBean.setFilter(new DosFilter(securityProperties.getDos().getFilter().getMaxRead(), @@ -207,6 +245,7 @@ public class SecurityManagedConfiguration { securityProperties.getDos().getFilter().getWhitelist(), securityProperties.getClients().getBlacklist(), securityProperties.getClients().getRemoteIpHeader())); filterRegBean.addUrlPatterns("/{tenant}/controller/v1/*", "/rest/*"); + return filterRegBean; } @@ -219,58 +258,49 @@ public class SecurityManagedConfiguration { @Bean @Order(100) public FilterRegistrationBean eTagFilter() { + final FilterRegistrationBean filterRegBean = new FilterRegistrationBean(); - // eclude the URLs for downloading artifacts, so no eTag is generated in - // the - // ShallowEtagHeaderFilter, just using the SH1 hash of the artifact - // itself as 'ETag', because - // otherwise the file will be copied in memory! + // Exclude the URLs for downloading artifacts, so no eTag is generated + // in the ShallowEtagHeaderFilter, just using the SH1 hash of the + // artifact itself as 'ETag', because otherwise the file will be copied + // in memory! filterRegBean.setFilter(new ExcludePathAwareShallowETagFilter( "/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download", "/{tenant}/controller/artifacts/**", "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/**")); + return filterRegBean; } - /** - * Security configuration for the REST management API of the health url. - * - * - */ - @Configuration - @Order(310) - public static class HealthSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(final HttpSecurity http) throws Exception { - http.regexMatcher("/system/health").csrf().disable().httpBasic().and().sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS); - } - } - /** * Security configuration for the REST management API. - * - * */ @Configuration @Order(350) public static class RestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { + @Autowired private UserAuthenticationFilter userAuthenticationFilter; + @Autowired private SystemManagement systemManagement; + @Autowired private TenantAware tenantAware; + @Autowired - private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties; + private SecurityProperties springSecurityProperties; @Override protected void configure(final HttpSecurity http) throws Exception { - HttpSecurity httpSec = http.regexMatcher("\\/rest.*|\\/system.*").csrf().disable(); + final BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint(); + basicAuthEntryPoint.setRealmName(springSecurityProperties.getBasic().getRealm()); + + HttpSecurity httpSec = http.regexMatcher("\\/rest.*|\\/system/admin.*").csrf().disable(); if (springSecurityProperties.isRequireSsl()) { httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and(); } + httpSec.addFilterBefore(new Filter() { @Override public void init(final FilterConfig filterConfig) throws ServletException { @@ -290,17 +320,17 @@ public class SecurityManagedConfiguration { }, RequestHeaderAuthenticationFilter.class) .addFilterAfter( new AuthenticationSuccessTenantMetadataCreationFilter(tenantAware, systemManagement), - RequestHeaderAuthenticationFilter.class) + SessionManagementFilter.class) .authorizeRequests().anyRequest().authenticated() - .antMatchers(RestConstants.BASE_SYSTEM_MAPPING + "/admin/**") - .hasAnyAuthority(SpPermission.SYSTEM_ADMIN).antMatchers(RestConstants.BASE_SYSTEM_MAPPING + "/**") - .hasAnyAuthority(SpPermission.SYSTEM_DIAG); + .antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/admin/**") + .hasAnyAuthority(SpPermission.SYSTEM_ADMIN); + + httpSec.httpBasic().and().exceptionHandling().authenticationEntryPoint(basicAuthEntryPoint); } } /** * {@link WebSecurityConfigurer} for external (management) access. - * */ @Configuration @Order(400) @@ -310,10 +340,13 @@ public class SecurityManagedConfiguration { private static final String XFRAME_OPTION_DENY = "DENY"; private static final String XFRAME_OPTION_SAMEORIGIN = "SAMEORIGIN"; private static final String XFAME_OPTION_ALLOW_FROM = "ALLOW-FROM"; + @Autowired private VaadinSecurityContext vaadinSecurityContext; + @Autowired private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties; + @Autowired private HawkbitSecurityProperties securityProperties; @@ -345,10 +378,13 @@ public class SecurityManagedConfiguration { */ @Bean public VaadinAuthenticationSuccessHandler redirectSaveHandler() { + final VaadinUrlAuthenticationSuccessHandler handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(); + handler.setRedirectStrategy(vaadinRedirectStrategy()); handler.setDefaultTargetUrl("/UI/"); handler.setTargetUrlParameter("r"); + return handler; } @@ -370,7 +406,8 @@ public class SecurityManagedConfiguration { // configuration xframe-option final String confXframeOption = securityProperties.getXframe().getOption(); final String confAllowFromUri = securityProperties.getXframe().getAllowfrom(); - if (confXframeOption.equals(XFAME_OPTION_ALLOW_FROM) && confAllowFromUri.isEmpty()) { + + if (XFAME_OPTION_ALLOW_FROM.equals(confXframeOption) && confAllowFromUri.isEmpty()) { // if allow-from option is specified but no allowFromUri throw // exception throw new IllegalStateException("hawkbit.server.security.xframe.option has been specified as ALLOW-FROM" @@ -379,9 +416,8 @@ public class SecurityManagedConfiguration { } // workaround regex: we need to exclude the URL /UI/HEARTBEAT here - // because we bound the - // vaadin application to /UI and not to root, described in - // vaadin-forum: + // because we bound the vaadin application to /UI and not to root, + // described in vaadin-forum: // https://vaadin.com/forum#!/thread/3200565. HttpSecurity httpSec = http.regexMatcher("(?!.*HEARTBEAT)^.*\\/UI.*$") // disable as CSRF is handled by Vaadin @@ -390,8 +426,9 @@ public class SecurityManagedConfiguration { if (springSecurityProperties.isRequireSsl()) { httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and(); } else { + LOG.info( - "\"******************\\n** Requires HTTPS Security has been disabled for UI, should only use for developing purposes **\\n******************\""); + "\"******************\\n** Requires HTTPS Security has been disabled for UI, should only be used for developing purposes **\\n******************\""); } // for UI integrator we allow frame integration on same origin @@ -440,9 +477,6 @@ public class SecurityManagedConfiguration { /** * A Websecruity config to handle and filter the download ids. - * - * - * */ @Configuration @EnableWebSecurity @@ -458,6 +492,7 @@ public class SecurityManagedConfiguration { @Override protected void configure(final HttpSecurity http) throws Exception { + final HttpDownloadAuthenticationFilter downloadIdAuthenticationFilter = new HttpDownloadAuthenticationFilter( downloadIdCache); downloadIdAuthenticationFilter.setAuthenticationManager(authenticationManager()); @@ -475,32 +510,21 @@ public class SecurityManagedConfiguration { auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider( ddiSecurityConfiguration.getRp().getTrustedIPs())); } - } - } /** * After a successful login on the UI we need to ensure to create the tenant * meta data within SP. - * - * */ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends VaadinUrlAuthenticationSuccessHandler { @Autowired private SystemManagement systemManagement; - /* - * (non-Javadoc) - * - * @see org.vaadin.spring.security.web.authentication. - * SavedRequestAwareVaadinAuthenticationSuccessHandler - * #onAuthenticationSuccess(org.springframework.security.core. - * Authentication) - */ @Override public void onAuthenticationSuccess(final Authentication authentication) throws Exception { + if (authentication.getClass().equals(TenantUserPasswordAuthenticationToken.class)) { systemManagement .getTenantMetadata(((TenantUserPasswordAuthenticationToken) authentication).getTenant().toString()); @@ -514,14 +538,13 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends // has been fixed. systemManagement.getTenantMetadata("DEFAULT"); } + super.onAuthenticationSuccess(authentication); } } /** * Sevletfilter to create metadata after successful authentication over RESTful. - * - * */ class AuthenticationSuccessTenantMetadataCreationFilter implements Filter { @@ -542,11 +565,13 @@ class AuthenticationSuccessTenantMetadataCreationFilter implements Filter { @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { + final String currentTenant = tenantAware.getCurrentTenant(); if (currentTenant != null) { // lazy initialize tenant meta data after successful authentication systemManagement.getTenantMetadata(currentTenant); } + chain.doFilter(request, response); } diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/web/ResourceControllerAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/web/ResourceControllerAutoConfiguration.java index 1d75510e4..ee54995c8 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/web/ResourceControllerAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/web/ResourceControllerAutoConfiguration.java @@ -8,21 +8,19 @@ */ package org.eclipse.hawkbit.autoconfigure.web; -import org.eclipse.hawkbit.controller.EnableDirectDeviceApi; -import org.eclipse.hawkbit.rest.resource.EnableRestResources; +import org.eclipse.hawkbit.ddi.EnableDdiApi; +import org.eclipse.hawkbit.mgmt.EnableMgmtApi; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** * Auto-Configuration for enabling the REST-Resources. - * - * * */ @Configuration -@ConditionalOnClass({ EnableDirectDeviceApi.class, EnableRestResources.class }) -@Import({ EnableDirectDeviceApi.class, EnableRestResources.class }) +@ConditionalOnClass({ EnableDdiApi.class, EnableMgmtApi.class }) +@Import({ EnableDdiApi.class, EnableMgmtApi.class }) public class ResourceControllerAutoConfiguration { } diff --git a/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories b/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories index 335054585..7df1f5ed2 100644 --- a/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories @@ -11,4 +11,5 @@ org.eclipse.hawkbit.autoconfigure.eventbus.EventBusAutoConfiguration,\ org.eclipse.hawkbit.autoconfigure.scheduling.AsyncConfigurerAutoConfiguration,\ org.eclipse.hawkbit.autoconfigure.cache.RedisAutoConfiguration,\ org.eclipse.hawkbit.autoconfigure.scheduling.ExecutorAutoConfiguration,\ -org.eclipse.hawkbit.autoconfigure.amqp.AmqpAutoConfiguration +org.eclipse.hawkbit.autoconfigure.amqp.AmqpAutoConfiguration,\ +org.eclipse.hawkbit.autoconfigure.security.InMemoryUserManagementConfiguration diff --git a/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties b/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties index 488777b8d..cb7793168 100644 --- a/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties +++ b/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties @@ -7,6 +7,9 @@ # http://www.eclipse.org/legal/epl-v10.html # +# Displayed basic auth realm +security.basic.realm=HawkBit + # JPA / Datasource spring.jpa.eclipselink.eclipselink.weaving=false spring.jpa.database=H2 @@ -27,12 +30,6 @@ vaadin.servlet.urlMapping=/UI/* vaadin.servlet.heartbeatInterval=60 vaadin.servlet.closeIdleSessions=false -# Defines the thread pool executor -hawkbit.threadpool.corethreads=5 -hawkbit.threadpool.maxthreads=20 -hawkbit.threadpool.idletimeout=10000 -hawkbit.threadpool.queuesize=20000 - # Defines the polling time for the controllers in HH:MM:SS notation hawkbit.controller.pollingTime=00:05:00 hawkbit.controller.pollingOverdueTime=00:05:00 @@ -44,4 +41,5 @@ hawkbit.controller.minPollingTime=00:00:30 # Configuration for RabbitMQ integration hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter_ttl hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter -hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver \ No newline at end of file +hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver +hawkbit.dmf.rabbitmq.authenticationReceiverQueue=authentication_receiver diff --git a/hawkbit-cache-redis/pom.xml b/hawkbit-cache-redis/pom.xml index 09567291b..637a6b49f 100644 --- a/hawkbit-cache-redis/pom.xml +++ b/hawkbit-cache-redis/pom.xml @@ -45,6 +45,12 @@ + + org.eclipse.hawkbit + hawkbit-repository-api + ${project.version} + test + org.springframework.boot spring-boot-starter-test diff --git a/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisConfiguration.java b/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisConfiguration.java index edc183b17..fc3364d81 100644 --- a/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisConfiguration.java +++ b/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisConfiguration.java @@ -15,6 +15,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.cache.CacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; @@ -50,8 +51,14 @@ public class RedisConfiguration { * @return the spring redis cache manager. */ @Bean + @Primary public CacheManager cacheManager() { - return new TenantAwareCacheManager(new RedisCacheManager(redisTemplate()), tenantAware); + return new TenantAwareCacheManager(directCacheManager(), tenantAware); + } + + @Bean(name = "directCacheManager") + public CacheManager directCacheManager() { + return new RedisCacheManager(redisTemplate()); } /** diff --git a/hawkbit-cache-redis/src/test/java/org/eclipse/hawkbit/cache/eventbus/EventDistributorTest.java b/hawkbit-cache-redis/src/test/java/org/eclipse/hawkbit/cache/eventbus/EventDistributorTest.java index c1ff54961..bebd82484 100644 --- a/hawkbit-cache-redis/src/test/java/org/eclipse/hawkbit/cache/eventbus/EventDistributorTest.java +++ b/hawkbit-cache-redis/src/test/java/org/eclipse/hawkbit/cache/eventbus/EventDistributorTest.java @@ -16,8 +16,8 @@ import static org.mockito.Mockito.verify; import java.util.Collection; -import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent; import org.eclipse.hawkbit.eventbus.event.EntityEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -56,7 +56,7 @@ public class EventDistributorTest { @Test public void distributeDistributedEventSendsToRedis() { - final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10); + final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L); underTest.distribute(event); // origin node ID should be set by distributing the event @@ -67,7 +67,7 @@ public class EventDistributorTest { @Test public void dontDistributeDistributedEventIfSameNode() { final String knownNodeId = EventDistributor.getNodeId(); - final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10); + final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L); event.setNodeId(knownNodeId); // test @@ -79,7 +79,7 @@ public class EventDistributorTest { @Test public void handleDistributedMessageFromRedis() { - final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10); + final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L); final String knownChannel = "someChannel"; underTest.handleMessage(event, knownChannel); @@ -90,7 +90,7 @@ public class EventDistributorTest { @Test public void handleDistributedMessageFilteredIfSameNodeId() { - final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10); + final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L); final String knownChannel = "someChannel"; event.setOriginNodeId(EventDistributor.getNodeId()); diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/event/DownloadProgressEvent.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/event/DownloadProgressEvent.java deleted file mode 100644 index 74679f02e..000000000 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/event/DownloadProgressEvent.java +++ /dev/null @@ -1,57 +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.eventbus.event; - -/** - * Event that contains an updated download progress for a given Action. - * - * - * - * - */ -public class DownloadProgressEvent extends AbstractDistributedEvent { - - private static final long serialVersionUID = 1L; - - private final Long statusId; - private final int progressPercent; - - /** - * Constructor. - * - * @param tenant - * the tenant for this event - * @param statusId - * of {@link UpdateActionStatus} - * @param progressPercent - * number (1-100) - */ - public DownloadProgressEvent(final String tenant, final Long statusId, final int progressPercent) { - // the revision of the DownloadProgressEvent is just equal the - // progressPercentage due the - // percentage is going from 0 to 100. - super(statusId, tenant); - this.statusId = statusId; - this.progressPercent = progressPercent; - } - - /** - * @return the statusId - */ - public Long getStatusId() { - return statusId; - } - - /** - * @return the progressPercent - */ - public int getProgressPercent() { - return progressPercent; - } -} diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java index 003b31cd7..5acd11463 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java @@ -24,147 +24,124 @@ public enum SpServerError { /** * */ - SP_REPO_ENTITY_ALRREADY_EXISTS("hawkbit.server.error.repo.entitiyAlreayExists", - "The given entity already exists in database"), + SP_REPO_ENTITY_ALRREADY_EXISTS("hawkbit.server.error.repo.entitiyAlreayExists", "The given entity already exists in database"), + + /** + * + */ + SP_REPO_INVALID_TARGET_ADDRESS("hawkbit.server.error.repo.invalidTargetAddress", "The target address is not well formed"), /** * */ - SP_REPO_ENTITY_NOT_EXISTS("hawkbit.server.error.repo.entitiyNotFound", - "The given entity does not exist in database"), + SP_REPO_ENTITY_NOT_EXISTS("hawkbit.server.error.repo.entitiyNotFound", "The given entity does not exist in database"), /** * */ - SP_REPO_CONCURRENT_MODIFICATION("hawkbit.server.error.repo.concurrentModification", - "The given entity has been changed by another user/session"), + SP_REPO_CONCURRENT_MODIFICATION("hawkbit.server.error.repo.concurrentModification", "The given entity has been changed by another user/session"), /** * */ - SP_REST_SORT_PARAM_SYNTAX("hawkbit.server.error.rest.param.sortParamSyntax", - "The given sort paramter is not well formed"), + SP_REST_SORT_PARAM_SYNTAX("hawkbit.server.error.rest.param.sortParamSyntax", "The given sort paramter is not well formed"), /** * */ - SP_REST_RSQL_SEARCH_PARAM_SYNTAX("hawkbit.server.error.rest.param.rsqlParamSyntax", - "The given search paramter is not well formed"), + SP_REST_RSQL_SEARCH_PARAM_SYNTAX("hawkbit.server.error.rest.param.rsqlParamSyntax", "The given search paramter is not well formed"), /** * */ - SP_REST_RSQL_PARAM_INVALID_FIELD("hawkbit.server.error.rest.param.rsqlInvalidField", - "The given search parameter field does not exist"), + SP_REST_RSQL_PARAM_INVALID_FIELD("hawkbit.server.error.rest.param.rsqlInvalidField", "The given search parameter field does not exist"), /** * */ - SP_REST_SORT_PARAM_INVALID_FIELD("hawkbit.server.error.rest.param.invalidField", - "The given sort parameter field does not exist"), + SP_REST_SORT_PARAM_INVALID_FIELD("hawkbit.server.error.rest.param.invalidField", "The given sort parameter field does not exist"), /** * */ - SP_REST_SORT_PARAM_INVALID_DIRECTION("hawkbit.server.error.rest.param.invalidDirection", - "The given sort parameter direction does not exist"), + SP_REST_SORT_PARAM_INVALID_DIRECTION("hawkbit.server.error.rest.param.invalidDirection", "The given sort parameter direction does not exist"), /** * */ - SP_REST_BODY_NOT_READABLE("hawkbit.server.error.rest.body.notReadable", - "The given request body is not well formed"), + SP_REST_BODY_NOT_READABLE("hawkbit.server.error.rest.body.notReadable", "The given request body is not well formed"), /** * */ - SP_ARTIFACT_UPLOAD_FAILED("hawkbit.server.error.artifact.uploadFailed", - "Upload of artifact failed with internal server error."), + SP_ARTIFACT_UPLOAD_FAILED("hawkbit.server.error.artifact.uploadFailed", "Upload of artifact failed with internal server error."), /** * */ - SP_ARTIFACT_UPLOAD_FAILED_MD5_MATCH("hawkbit.server.error.artifact.uploadFailed.checksum.md5.match", - "Upload of artifact failed as the provided MD5 checksum did not match with the provided artifact."), + SP_ARTIFACT_UPLOAD_FAILED_MD5_MATCH("hawkbit.server.error.artifact.uploadFailed.checksum.md5.match", "Upload of artifact failed as the provided MD5 checksum did not match with the provided artifact."), /** * */ - SP_ARTIFACT_UPLOAD_FAILED_SHA1_MATCH("hawkbit.server.error.artifact.uploadFailed.checksum.sha1.match", - "Upload of artifact failed as the provided SHA1 checksum did not match with the provided artifact."), + SP_ARTIFACT_UPLOAD_FAILED_SHA1_MATCH("hawkbit.server.error.artifact.uploadFailed.checksum.sha1.match", "Upload of artifact failed as the provided SHA1 checksum did not match with the provided artifact."), /** * */ - SP_DS_CREATION_FAILED_MISSING_MODULE("hawkbit.server.error.distributionset.creationFailed.missingModule", - "Creation if Distribution Set failed as module is missing that is configured as mandatory."), + SP_DS_CREATION_FAILED_MISSING_MODULE("hawkbit.server.error.distributionset.creationFailed.missingModule", "Creation if Distribution Set failed as module is missing that is configured as mandatory."), /** * */ - SP_ARTIFACT_UPLOAD_FILE_LIMIT_EXCEEDED("hawkbit.server.error.artifact.uploadFailed.sizelimitexceeded", - "Upload of artifact failed as the file exceeds its maximum permitted size"), - /** - * - */ SP_INSUFFICIENT_PERMISSION("hawkbit.server.error.insufficientpermission", "Insufficient Permission"), /** * */ - SP_ARTIFACT_DELETE_FAILED("hawkbit.server.error.artifact.deleteFailed", - "Deletion of artifact failed with internal server error."), + SP_ARTIFACT_DELETE_FAILED("hawkbit.server.error.artifact.deleteFailed", "Deletion of artifact failed with internal server error."), /** * */ - SP_ARTIFACT_LOAD_FAILED("hawkbit.server.error.artifact.loadFailed", - "Load of artifact failed with internal server error."), + SP_ARTIFACT_LOAD_FAILED("hawkbit.server.error.artifact.loadFailed", "Load of artifact failed with internal server error."), /** * */ - SP_ACTION_STATUS_TO_MANY_ENTRIES("hawkbit.server.error.action.status.tooManyEntries", - "Too many status entries have been inserted."), + SP_ACTION_STATUS_TO_MANY_ENTRIES("hawkbit.server.error.action.status.tooManyEntries", "Too many status entries have been inserted."), /** * */ - SP_ATTRIBUTES_TO_MANY_ENTRIES("hawkbit.server.error.target.attributes.tooManyEntries", - "Too many attribute entries have been inserted."), + SP_ATTRIBUTES_TO_MANY_ENTRIES("hawkbit.server.error.target.attributes.tooManyEntries", "Too many attribute entries have been inserted."), /** * error message, which describes that the action can not be canceled cause * the action is inactive. */ - SP_ACTION_NOT_CANCELABLE("hawkbit.server.error.action.notcancelable", - "Only active actions which are in status pending are canceable."), + SP_ACTION_NOT_CANCELABLE("hawkbit.server.error.action.notcancelable", "Only active actions which are in status pending are canceable."), /** * error message, which describes that the action can not be force quit * cause the action is inactive. */ - SP_ACTION_NOT_FORCE_QUITABLE("hawkbit.server.error.action.notforcequitable", - "Only active actions which are in status pending can be force quit."), + SP_ACTION_NOT_FORCE_QUITABLE("hawkbit.server.error.action.notforcequitable", "Only active actions which are in status pending can be force quit."), /** * */ - SP_DS_INCOMPLETE("hawkbit.server.error.distributionset.incomplete", - "Distribution set is assigned to a a target that is incomplete (i.e. mandatory modules are missing)"), + SP_DS_INCOMPLETE("hawkbit.server.error.distributionset.incomplete", "Distribution set is assigned to a a target that is incomplete (i.e. mandatory modules are missing)"), /** * */ - SP_DS_TYPE_UNDEFINED("hawkbit.server.error.distributionset.type.undefined", - "Distribution set type is not yet defined. Modules cannot be added until definition."), + SP_DS_TYPE_UNDEFINED("hawkbit.server.error.distributionset.type.undefined", "Distribution set type is not yet defined. Modules cannot be added until definition."), /** * */ - SP_DS_MODULE_UNSUPPORTED("hawkbit.server.error.distributionset.modules.unsupported", - "Distribution set type does not contain the given module, i.e. is incompatible."), + SP_DS_MODULE_UNSUPPORTED("hawkbit.server.error.distributionset.modules.unsupported", "Distribution set type does not contain the given module, i.e. is incompatible."), /** * */ - SP_REPO_TENANT_NOT_EXISTS("hawkbit.server.error.repo.tenantNotExists", - "The entity cannot be inserted due the tenant does not exists"), + SP_REPO_TENANT_NOT_EXISTS("hawkbit.server.error.repo.tenantNotExists", "The entity cannot be inserted due the tenant does not exists"), /** * @@ -174,14 +151,12 @@ public enum SpServerError { /** * */ - SP_REPO_ENTITY_READ_ONLY("hawkbit.server.error.entityreadonly", - "The given entity is read only and the change cannot be completed."), + SP_REPO_ENTITY_READ_ONLY("hawkbit.server.error.entityreadonly", "The given entity is read only and the change cannot be completed."), /** * */ - SP_CONFIGURATION_VALUE_INVALID("hawkbit.server.error.configValueInvalid", - "The given configuration value is invalid."), + SP_CONFIGURATION_VALUE_INVALID("hawkbit.server.error.configValueInvalid", "The given configuration value is invalid."), /** * */ @@ -190,8 +165,7 @@ public enum SpServerError { /** * */ - SP_ROLLOUT_ILLEGAL_STATE("hawkbit.server.error.rollout.illegalstate", - "The rollout is currently in the wrong state for the current operation"); + SP_ROLLOUT_ILLEGAL_STATE("hawkbit.server.error.rollout.illegalstate", "The rollout is currently in the wrong state for the current operation"); private final String key; private final String message; diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/TargetFields.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/TargetFields.java index 0a696fdb6..472c161ff 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/TargetFields.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/TargetFields.java @@ -64,7 +64,12 @@ public enum TargetFields implements FieldNameProvider { /** * The tags field. */ - TAG("tags.name"); + TAG("tags.name"), + + /** + * Last time the target or DMF client polled. + */ + LASTCONTROLLERREQUESTAT("targetInfo.lastTargetQuery"); private final String fieldName; private List subEntityAttribues; diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationKey.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationKey.java index 402185be3..d68e963be 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationKey.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationKey.java @@ -30,60 +30,45 @@ public enum TenantConfigurationKey { /** * boolean value {@code true} {@code false}. */ - AUTHENTICATION_MODE_HEADER_ENABLED("authentication.header.enabled", - "hawkbit.server.ddi.security.authentication.header.enabled", Boolean.class, Boolean.FALSE.toString(), - TenantConfigurationBooleanValidator.class), + AUTHENTICATION_MODE_HEADER_ENABLED("authentication.header.enabled", "hawkbit.server.ddi.security.authentication.header.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class), /** * */ - AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME("authentication.header.authority", - "hawkbit.server.ddi.security.authentication.header.authority", String.class, Boolean.FALSE.toString(), - TenantConfigurationStringValidator.class), + AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME("authentication.header.authority", "hawkbit.server.ddi.security.authentication.header.authority", String.class, Boolean.FALSE.toString(), TenantConfigurationStringValidator.class), /** * boolean value {@code true} {@code false}. */ - AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED("authentication.targettoken.enabled", - "hawkbit.server.ddi.security.authentication.targettoken.enabled", Boolean.class, Boolean.FALSE.toString(), - TenantConfigurationBooleanValidator.class), + AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED("authentication.targettoken.enabled", "hawkbit.server.ddi.security.authentication.targettoken.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class), /** * boolean value {@code true} {@code false}. */ - AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED("authentication.gatewaytoken.enabled", - "hawkbit.server.ddi.security.authentication.gatewaytoken.enabled", Boolean.class, Boolean.FALSE.toString(), - TenantConfigurationBooleanValidator.class), + AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED("authentication.gatewaytoken.enabled", "hawkbit.server.ddi.security.authentication.gatewaytoken.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class), /** * string value which holds the name of the security token key. */ - AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME("authentication.gatewaytoken.name", - "hawkbit.server.ddi.security.authentication.gatewaytoken.name", String.class, null, - TenantConfigurationStringValidator.class), + AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME("authentication.gatewaytoken.name", "hawkbit.server.ddi.security.authentication.gatewaytoken.name", String.class, null, TenantConfigurationStringValidator.class), /** * string value which holds the actual security-key of the gateway security * token. */ - AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY("authentication.gatewaytoken.key", - "hawkbit.server.ddi.security.authentication.gatewaytoken.key", String.class, null, - TenantConfigurationStringValidator.class), + AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY("authentication.gatewaytoken.key", "hawkbit.server.ddi.security.authentication.gatewaytoken.key", String.class, null, TenantConfigurationStringValidator.class), /** * string value which holds the polling time interval in the format HH:mm:ss */ - POLLING_TIME_INTERVAL("pollingTime", "hawkbit.controller.pollingTime", String.class, null, - TenantConfigurationPollingDurationValidator.class), + POLLING_TIME_INTERVAL("pollingTime", "hawkbit.controller.pollingTime", String.class, null, TenantConfigurationPollingDurationValidator.class), /** * string value which holds the polling time interval in the format HH:mm:ss */ - POLLING_OVERDUE_TIME_INTERVAL("pollingOverdueTime", "hawkbit.controller.pollingOverdueTime", String.class, null, - TenantConfigurationPollingDurationValidator.class), + POLLING_OVERDUE_TIME_INTERVAL("pollingOverdueTime", "hawkbit.controller.pollingOverdueTime", String.class, null, TenantConfigurationPollingDurationValidator.class), /** * boolean value {@code true} {@code false}. */ - ANONYMOUS_DOWNLOAD_MODE_ENABLED("anonymous.download.enabled", "hawkbit.server.download.anonymous.enabled", - Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class); + ANONYMOUS_DOWNLOAD_MODE_ENABLED("anonymous.download.enabled", "hawkbit.server.download.anonymous.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class); private final String keyName; private final String defaultKeyName; @@ -140,8 +125,9 @@ public enum TenantConfigurationKey { * @return the data type of the tenant configuration value. (e.g. * Integer.class, String.class) */ - public Class getDataType() { - return dataType; + @SuppressWarnings("unchecked") + public Class getDataType() { + return (Class) dataType; } /** diff --git a/hawkbit-ddi-api/README.md b/hawkbit-ddi-api/README.md new file mode 100644 index 000000000..b47b74895 --- /dev/null +++ b/hawkbit-ddi-api/README.md @@ -0,0 +1,12 @@ +# Eclipse.IoT hawkBit - DDI API + +The Direct Device Integration (DDI) API is used by devices for communicating with the HawkBit Update Server through HTTP. + +# Compile + +#### Build hawkbit-ddi-api + +``` +$ cd hawkbit/hawkbit-ddi-api +$ mvn clean install +``` diff --git a/hawkbit-ddi-api/pom.xml b/hawkbit-ddi-api/pom.xml new file mode 100644 index 000000000..969f0d930 --- /dev/null +++ b/hawkbit-ddi-api/pom.xml @@ -0,0 +1,45 @@ + + + + 4.0.0 + + org.eclipse.hawkbit + hawkbit-parent + 0.2.0-SNAPSHOT + + hawkbit-ddi-api + hawkBit :: DDI API + + + + org.springframework.hateoas + spring-hateoas + + + com.fasterxml.jackson.core + jackson-annotations + + + javax.validation + validation-api + + + org.hibernate + hibernate-validator + + + org.springframework.security + spring-security-web + + + diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/ActionFeedback.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiActionFeedback.java similarity index 60% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/ActionFeedback.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiActionFeedback.java index 3fe511e49..cbb45b788 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/ActionFeedback.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiActionFeedback.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; import javax.validation.constraints.NotNull; @@ -15,16 +15,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; /** - * *

- * After the SP Target has executed an action, received by a GET(URL) request it - * reports the completion of it to the SP Server with a action status message, - * i.e. with a PUT message to the feedback channel, i.e. PUT URL/feedback. This - * message could be used not only at the end of execution but also as status - * updates during a longer lasting execution period. The format of each action - * answer message is defined below at each action. But it is expected, that the - * contents of the message answers have all a similar structure: The content - * starts with a generic header and additional elements. * + * After the HawkBit Target has executed an action, received by a GET(URL) + * request it reports the completion of it to the HawkBit Server with a action + * status message, i.e. with a PUT message to the feedback channel, i.e. PUT + * URL/feedback. This message could be used not only at the end of execution but + * also as status updates during a longer lasting execution period. The format + * of each action answer message is defined below at each action. But it is + * expected, that the contents of the message answers have all a similar + * structure: The content starts with a generic header and additional elements. + * * *

* *

@@ -35,12 +35,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; * */ @JsonIgnoreProperties(ignoreUnknown = true) -public class ActionFeedback { +public class DdiActionFeedback { private final Long id; private final String time; @NotNull - private final Status status; + private final DdiStatus status; /** * Constructor. @@ -53,8 +53,8 @@ public class ActionFeedback { * is the feedback itself */ @JsonCreator - public ActionFeedback(@JsonProperty("id") final Long id, @JsonProperty("time") final String time, - @JsonProperty("status") final Status status) { + public DdiActionFeedback(@JsonProperty("id") final Long id, @JsonProperty("time") final String time, + @JsonProperty("status") final DdiStatus status) { this.id = id; this.time = time; this.status = status; @@ -68,15 +68,10 @@ public class ActionFeedback { return time; } - public Status getStatus() { + public DdiStatus getStatus() { return status; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ @Override public String toString() { return "ActionFeedback [id=" + id + ", time=" + time + ", status=" + status + "]"; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Artifact.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiArtifact.java similarity index 61% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Artifact.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiArtifact.java index b995491d9..5fc911946 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Artifact.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiArtifact.java @@ -6,72 +6,50 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; import javax.validation.constraints.NotNull; -import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactHash; import org.springframework.hateoas.ResourceSupport; import com.fasterxml.jackson.annotation.JsonProperty; /** - * Download information for all artifacts related to a specific {@link Chunk}. - * + * Download information for all artifacts related to a specific {@link DdiChunk} + * . */ -public class Artifact extends ResourceSupport { +public class DdiArtifact extends ResourceSupport { @NotNull @JsonProperty private String filename; @JsonProperty - private ArtifactHash hashes; + private DdiArtifactHash hashes; @JsonProperty private Long size; - /** - * @return the hashes - */ - public ArtifactHash getHashes() { + public DdiArtifactHash getHashes() { return hashes; } - /** - * @param hashes - * the hashes to set - */ - public void setHashes(final ArtifactHash hashes) { + public void setHashes(final DdiArtifactHash hashes) { this.hashes = hashes; } - /** - * @return the fileName - */ public String getFilename() { return filename; } - /** - * @param fileName - * the fileName to set - */ public void setFilename(final String fileName) { filename = fileName; } - /** - * @return the size - */ public Long getSize() { return size; } - /** - * @param size - * the size to set - */ public void setSize(final Long size) { this.size = size; } diff --git a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiArtifactHash.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiArtifactHash.java new file mode 100644 index 000000000..9541055f8 --- /dev/null +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiArtifactHash.java @@ -0,0 +1,57 @@ +/** + * 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.ddi.json.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Hashes for given Artifact. + * + * + */ +public class DdiArtifactHash { + + @JsonProperty + private String sha1; + + @JsonProperty + private String md5; + + /** + * Default constructor. + */ + public DdiArtifactHash() { + } + + /** + * Public constructor. + * + * @param sha1 + * @param md5 + */ + public DdiArtifactHash(final String sha1, final String md5) { + this.sha1 = sha1; + this.md5 = md5; + } + + /** + * @return the sha1 + */ + public String getSha1() { + return sha1; + } + + /** + * @return the md5 + */ + public String getMd5() { + return md5; + } + +} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Cancel.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiCancel.java similarity index 66% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Cancel.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiCancel.java index 77055828f..c117dea14 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Cancel.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiCancel.java @@ -6,53 +6,42 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; import javax.validation.constraints.NotNull; /** * Cancel action to be provided to the target. - * */ -public class Cancel { +public class DdiCancel { + private final String id; @NotNull - private final CancelActionToStop cancelAction; + private final DdiCancelActionToStop cancelAction; /** * Parameterized constructor. * * @param id - * of the {@link CancelAction} + * of the cancel action * @param cancelAction * the action */ - public Cancel(final String id, final CancelActionToStop cancelAction) { + public DdiCancel(final String id, final DdiCancelActionToStop cancelAction) { super(); this.id = id; this.cancelAction = cancelAction; } - /** - * @return the id - */ public String getId() { return id; } - /** - * @return the cancelAction - */ - public CancelActionToStop getCancelAction() { + public DdiCancelActionToStop getCancelAction() { return cancelAction; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ @Override public String toString() { return "Cancel [id=" + id + ", cancelAction=" + cancelAction + "]"; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/CancelActionToStop.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiCancelActionToStop.java similarity index 62% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/CancelActionToStop.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiCancelActionToStop.java index 9b954aa57..3ab8d6b55 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/CancelActionToStop.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiCancelActionToStop.java @@ -6,17 +6,14 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; import javax.validation.constraints.NotNull; -import org.eclipse.hawkbit.repository.model.Action; - /** - * The {@link Action} that has to be stopped by the target. - * + * The action that has to be stopped by the target. */ -public class CancelActionToStop { +public class DdiCancelActionToStop { @NotNull private final String stopId; @@ -25,25 +22,17 @@ public class CancelActionToStop { * Parameterized constructor. * * @param stopId - * ID of the {@link Action} to be stoppedW + * ID of the action to be stoppedW */ - public CancelActionToStop(final String stopId) { + public DdiCancelActionToStop(final String stopId) { super(); this.stopId = stopId; } - /** - * @return the stopId - */ public String getStopId() { return stopId; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ @Override public String toString() { return "CancelAction [stopId=" + stopId + "]"; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Chunk.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiChunk.java similarity index 70% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Chunk.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiChunk.java index 66809bfbb..78de8591d 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Chunk.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiChunk.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; import java.util.List; @@ -14,20 +14,23 @@ import javax.validation.constraints.NotNull; /** * Deployment chunks. - * */ -public class Chunk { +public class DdiChunk { @NotNull - private final String part; + private String part; @NotNull - private final String version; + private String version; @NotNull - private final String name; + private String name; - private final List artifacts; + private List artifacts; + + public DdiChunk() { + + } /** * Constructor. @@ -40,9 +43,8 @@ public class Chunk { * of the artifact * @param artifacts * download information - * */ - public Chunk(final String part, final String version, final String name, final List artifacts) { + public DdiChunk(final String part, final String version, final String name, final List artifacts) { super(); this.part = part; this.version = version; @@ -58,17 +60,11 @@ public class Chunk { return version; } - /** - * @return the name - */ public String getName() { return name; } - /** - * @return the artifacts - */ - public List getArtifacts() { + public List getArtifacts() { return artifacts; } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Config.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiConfig.java similarity index 51% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Config.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiConfig.java index 62907b26d..5ec1b4dde 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Config.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiConfig.java @@ -6,15 +6,22 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; /** * Standard configuration for the target. - * */ -public class Config { +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class DdiConfig { - private final Polling polling; + @JsonProperty + private DdiPolling polling; /** * Constructor. @@ -22,12 +29,16 @@ public class Config { * @param polling * configuration of the SP target */ - public Config(final Polling polling) { + public DdiConfig(final DdiPolling polling) { super(); this.polling = polling; } - public Polling getPolling() { + public DdiConfig() { + + } + + public DdiPolling getPolling() { return polling; } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/ConfigData.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiConfigData.java similarity index 75% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/ConfigData.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiConfigData.java index b7c330167..a16ddf064 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/ConfigData.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiConfigData.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; import java.util.Map; @@ -17,9 +17,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; /** * Feedback channel for ConfigData action. - * */ -public class ConfigData extends ActionFeedback { +public class DdiConfigData extends DdiActionFeedback { @NotEmpty private final Map data; @@ -35,28 +34,19 @@ public class ConfigData extends ActionFeedback { * is the feedback itself * @param data * contains the attributes. - * */ @JsonCreator - public ConfigData(@JsonProperty(value = "id") final Long id, @JsonProperty(value = "time") final String time, - @JsonProperty(value = "status") final Status status, + public DdiConfigData(@JsonProperty(value = "id") final Long id, @JsonProperty(value = "time") final String time, + @JsonProperty(value = "status") final DdiStatus status, @JsonProperty(value = "data") final Map data) { super(id, time, status); this.data = data; } - /** - * @return the data - */ public Map getData() { return data; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ @Override public String toString() { return "ConfigData [data=" + data + ", toString()=" + super.toString() + "]"; diff --git a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiControllerBase.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiControllerBase.java new file mode 100644 index 000000000..3f160157c --- /dev/null +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiControllerBase.java @@ -0,0 +1,47 @@ +/** + * 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.ddi.json.model; + +import org.springframework.hateoas.ResourceSupport; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * {@link DdiControllerBase} resource content. + */ +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class DdiControllerBase extends ResourceSupport { + + @JsonProperty + private DdiConfig config; + + /** + * Constructor. + * + * @param config + * configuration of the SP target + */ + public DdiControllerBase(final DdiConfig config) { + super(); + this.config = config; + } + + public DdiControllerBase() { + + } + + public DdiConfig getConfig() { + return config; + } + +} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Deployment.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiDeployment.java similarity index 72% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Deployment.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiDeployment.java index 57ead963c..f72083d7a 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Deployment.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiDeployment.java @@ -6,25 +6,26 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; import java.util.List; -import org.eclipse.hawkbit.repository.model.Action; - import com.fasterxml.jackson.annotation.JsonValue; /** - * Detailed {@link UpdateAction} information. - * + * Detailed update action information. */ -public class Deployment { +public class DdiDeployment { - private final HandlingType download; + private HandlingType download; - private final HandlingType update; + private HandlingType update; - private final List chunks; + private List chunks; + + public DdiDeployment() { + + } /** * Constructor. @@ -36,7 +37,7 @@ public class Deployment { * @param chunks * to handle. */ - public Deployment(final HandlingType download, final HandlingType update, final List chunks) { + public DdiDeployment(final HandlingType download, final HandlingType update, final List chunks) { super(); this.download = download; this.update = update; @@ -51,15 +52,15 @@ public class Deployment { return update; } - public List getChunks() { + public List getChunks() { return chunks; } /** - * The handling type for the update {@link Action}. - * + * The handling type for the update action. */ public enum HandlingType { + /** * Not necessary for the command. */ @@ -81,20 +82,12 @@ public class Deployment { this.name = name; } - /** - * @return the name - */ @JsonValue public String getName() { return name; } } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ @Override public String toString() { return "Deployment [download=" + download + ", update=" + update + ", chunks=" + chunks + "]"; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/DeploymentBase.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiDeploymentBase.java similarity index 66% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/DeploymentBase.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiDeploymentBase.java index ea3e1caa5..8f1116b1b 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/DeploymentBase.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiDeploymentBase.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; import javax.validation.constraints.NotNull; @@ -15,40 +15,38 @@ import org.springframework.hateoas.ResourceSupport; import com.fasterxml.jackson.annotation.JsonProperty; /** - * {@link UpdateAction} resource. - * + * Update action resource. */ -public class DeploymentBase extends ResourceSupport { +public class DdiDeploymentBase extends ResourceSupport { @JsonProperty("id") @NotNull - private final String deplyomentId; + private String deplyomentId; @NotNull - private final Deployment deployment; + private DdiDeployment deployment; /** * Constructor. * * @param id - * of the {@link UpdateAction} + * of the update action * @param deployment * details. */ - public DeploymentBase(final String id, final Deployment deployment) { + public DdiDeploymentBase(final String id, final DdiDeployment deployment) { deplyomentId = id; this.deployment = deployment; } - public Deployment getDeployment() { + public DdiDeploymentBase() { + + } + + public DdiDeployment getDeployment() { return deployment; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ @Override public String toString() { return "DeploymentBase [id=" + deplyomentId + ", deployment=" + deployment + "]"; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Polling.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiPolling.java similarity index 53% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Polling.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiPolling.java index 4e0854d98..489178be8 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Polling.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiPolling.java @@ -6,15 +6,22 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; /** * Polling interval for the SP target. - * */ -public class Polling { +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class DdiPolling { - private final String sleep; + @JsonProperty + private String sleep; /** * Constructor. @@ -22,11 +29,14 @@ public class Polling { * @param sleep * between polls */ - public Polling(final String sleep) { + public DdiPolling(final String sleep) { super(); this.sleep = sleep; } + public DdiPolling() { + } + public String getSleep() { return sleep; } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Progress.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiProgress.java similarity index 81% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Progress.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiProgress.java index 096231c7b..cf73fc5c0 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Progress.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiProgress.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; import javax.validation.constraints.NotNull; @@ -16,9 +16,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; /** * Action fulfillment progress by means of gives the achieved amount of maximal * of possible levels. - * */ -public class Progress { +public class DdiProgress { @NotNull private final Integer cnt; @@ -34,7 +33,7 @@ public class Progress { * maximum levels */ @JsonCreator - public Progress(@JsonProperty("cnt") final Integer cnt, @JsonProperty("of") final Integer of) { + public DdiProgress(@JsonProperty("cnt") final Integer cnt, @JsonProperty("of") final Integer of) { super(); this.cnt = cnt; this.of = of; @@ -48,11 +47,6 @@ public class Progress { return of; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ @Override public String toString() { return "Progress [cnt=" + cnt + ", of=" + of + "]"; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Result.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiResult.java similarity index 81% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Result.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiResult.java index b5dd22aaa..36f0d134c 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Result.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiResult.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; import org.hibernate.validator.constraints.NotEmpty; @@ -17,15 +17,13 @@ import com.fasterxml.jackson.annotation.JsonValue; /** * Result information of the action progress which can by an intermediate or * final update. - * - * */ -public class Result { +public class DdiResult { @NotEmpty private final FinalResult finished; - private final Progress progress; + private final DdiProgress progress; /** * Constructor. @@ -36,8 +34,8 @@ public class Result { * if not yet finished */ @JsonCreator - public Result(@JsonProperty("finished") final FinalResult finished, - @JsonProperty("progress") final Progress progress) { + public DdiResult(@JsonProperty("finished") final FinalResult finished, + @JsonProperty("progress") final DdiProgress progress) { super(); this.finished = finished; this.progress = progress; @@ -47,7 +45,7 @@ public class Result { return finished; } - public Progress getProgress() { + public DdiProgress getProgress() { return progress; } @@ -77,21 +75,12 @@ public class Result { this.name = name; } - /** - * @return the name - */ @JsonValue public String getName() { return name; } - } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ @Override public String toString() { return "Result [finished=" + finished + ", progress=" + progress + "]"; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Status.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiStatus.java similarity index 84% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Status.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiStatus.java index df1622e31..cb9b57187 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/Status.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiStatus.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller.model; +package org.eclipse.hawkbit.ddi.json.model; import java.util.List; @@ -18,15 +18,14 @@ import com.fasterxml.jackson.annotation.JsonValue; /** * Details status information concerning the action processing. - * */ -public class Status { +public class DdiStatus { @NotNull private final ExecutionStatus execution; @NotNull - private final Result result; + private final DdiResult result; private final List details; @@ -41,8 +40,8 @@ public class Status { * as optional addition */ @JsonCreator - public Status(@JsonProperty("execution") final ExecutionStatus execution, - @JsonProperty("result") final Result result, @JsonProperty("details") final List details) { + public DdiStatus(@JsonProperty("execution") final ExecutionStatus execution, + @JsonProperty("result") final DdiResult result, @JsonProperty("details") final List details) { super(); this.execution = execution; this.result = result; @@ -53,7 +52,7 @@ public class Status { return execution; } - public Result getResult() { + public DdiResult getResult() { return result; } @@ -103,20 +102,12 @@ public class Status { this.name = name; } - /** - * @return the name - */ @JsonValue public String getName() { return name; } } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ @Override public String toString() { return "Status [execution=" + execution + ", result=" + result + ", details=" + details + "]"; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ControllerConstants.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRestConstants.java similarity index 57% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ControllerConstants.java rename to hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRestConstants.java index fd7f125c5..25be5b1f8 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ControllerConstants.java +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRestConstants.java @@ -6,24 +6,18 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller; +package org.eclipse.hawkbit.ddi.rest.api; /** - * - * - * + * Constants for the direct device integration rest resources. */ -public final class ControllerConstants { +public final class DdiRestConstants { + /** * The base URL mapping of the direct device integration rest resources. */ public static final String BASE_V1_REQUEST_MAPPING = "/{tenant}/controller/v1"; - /** - * The base URL mapping of the artifact repository rest resources. - */ - public static final String ARTIFACTS_V1_REQUEST_MAPPING = "/{tenant}/controller/artifacts/v1"; - /** * Deployment action resources. */ @@ -37,30 +31,19 @@ public final class ControllerConstants { /** * Feedback channel. */ - static final String FEEDBACK = "feedback"; + public static final String FEEDBACK = "feedback"; + + /** + * File suffix for MDH hash download (see Linux md5sum). + */ + public static final String ARTIFACT_MD5_DWNL_SUFFIX = ".MD5SUM"; /** * Config data action resources. */ public static final String CONFIG_DATA_ACTION = "configData"; - /** - * The artifact URL mapping rest resource. - */ - static final String ARTIFACT_DOWNLOAD = "artifact"; - - /** - * The artifact by filename URL mapping rest resource. - */ - static final String ARTIFACT_DOWNLOAD_BY_FILENAME = "/filename"; - - /** - * File suffix for MDH hash download (see Linux md5sum). - */ - static final String ARTIFACT_MD5_DWNL_SUFFIX = ".MD5SUM"; - - // constant class, private constructor. - private ControllerConstants() { - + private DdiRestConstants() { + // constant class, private constructor. } } diff --git a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRootControllerRestApi.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRootControllerRestApi.java new file mode 100644 index 000000000..67436c3ca --- /dev/null +++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRootControllerRestApi.java @@ -0,0 +1,212 @@ +/** + * 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.ddi.rest.api; + +import java.io.InputStream; +import java.lang.annotation.Target; +import java.util.List; + +import javax.validation.Valid; + +import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback; +import org.eclipse.hawkbit.ddi.json.model.DdiArtifact; +import org.eclipse.hawkbit.ddi.json.model.DdiCancel; +import org.eclipse.hawkbit.ddi.json.model.DdiConfigData; +import org.eclipse.hawkbit.ddi.json.model.DdiControllerBase; +import org.eclipse.hawkbit.ddi.json.model.DdiDeploymentBase; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * REST resource handling for root controller CRUD operations. + */ +@RequestMapping(DdiRestConstants.BASE_V1_REQUEST_MAPPING) +public interface DdiRootControllerRestApi { + + /** + * Returns all artifacts of a given software module and target. + * + * @param targetid + * of the target that matches to controller id + * @param softwareModuleId + * of the software module + * @return the response + */ + @RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts", produces = { + "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity> getSoftwareModulesArtifacts( + @PathVariable("targetid") final String targetid, + @PathVariable("softwareModuleId") final Long softwareModuleId); + + /** + * Root resource for an individual {@link Target}. + * + * @param targetid + * of the target that matches to controller id + * @param request + * the HTTP request injected by spring + * @return the response + */ + @RequestMapping(method = RequestMethod.GET, value = "/{targetid}", produces = { "application/hal+json", + MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity getControllerBase(@PathVariable("targetid") final String targetid); + + /** + * Handles GET {@link DdiArtifact} download request. This could be full or + * partial (as specified by RFC7233 (Range Requests)) download request. + * + * @param targetid + * of the related target + * @param softwareModuleId + * of the parent software module + * @param fileName + * of the related local artifact + * @param response + * of the servlet + * @param request + * from the client + * + * @return response of the servlet which in case of success is status code + * {@link HttpStatus#OK} or in case of partial download + * {@link HttpStatus#PARTIAL_CONTENT}. + */ + @RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{fileName}") + ResponseEntity downloadArtifact(@PathVariable("targetid") final String targetid, + @PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("fileName") final String fileName); + + /** + * Handles GET {@link DdiArtifact} MD5 checksum file download request. + * + * @param targetid + * of the related target + * @param softwareModuleId + * of the parent software module + * @param fileName + * of the related local artifact + * @param response + * of the servlet + * @param request + * the HTTP request injected by spring + * + * @return {@link ResponseEntity} with status {@link HttpStatus#OK} if + * successful + */ + @RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{fileName}" + + DdiRestConstants.ARTIFACT_MD5_DWNL_SUFFIX, produces = MediaType.TEXT_PLAIN_VALUE) + ResponseEntity downloadArtifactMd5(@PathVariable("targetid") final String targetid, + @PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("fileName") final String fileName); + + /** + * Resource for software module. + * + * @param targetid + * of the target that matches to controller id + * @param actionId + * of the {@link DdiDeploymentBase} that matches to active + * actions. + * @param resource + * an hashcode of the resource which indicates if the action has + * been changed, e.g. from 'soft' to 'force' and the eTag needs + * to be re-generated + * @param request + * the HTTP request injected by spring + * @return the response + */ + @RequestMapping(value = "/{targetid}/" + DdiRestConstants.DEPLOYMENT_BASE_ACTION + + "/{actionId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + ResponseEntity getControllerBasedeploymentAction( + @PathVariable("targetid") @NotEmpty final String targetid, + @PathVariable("actionId") @NotEmpty final Long actionId, + @RequestParam(value = "c", required = false, defaultValue = "-1") final int resource); + + /** + * This is the feedback channel for the {@link DdiDeploymentBase} action. + * + * @param feedback + * to provide + * @param targetid + * of the target that matches to controller id + * @param actionId + * of the action we have feedback for + * @param request + * the HTTP request injected by spring + * + * @return the response + */ + @RequestMapping(value = "/{targetid}/" + DdiRestConstants.DEPLOYMENT_BASE_ACTION + "/{actionId}/" + + DdiRestConstants.FEEDBACK, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) + ResponseEntity postBasedeploymentActionFeedback(@Valid @RequestBody final DdiActionFeedback feedback, + @PathVariable("targetid") final String targetid, @PathVariable("actionId") @NotEmpty final Long actionId); + + /** + * This is the feedback channel for the config data action. + * + * @param configData + * as body + * @param targetid + * to provide data for + * @param request + * the HTTP request injected by spring + * + * @return status of the request + */ + @RequestMapping(value = "/{targetid}/" + + DdiRestConstants.CONFIG_DATA_ACTION, method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE) + ResponseEntity putConfigData(@Valid @RequestBody final DdiConfigData configData, + @PathVariable("targetid") final String targetid); + + /** + * RequestMethod.GET method for the {@link DdiCancel} action. + * + * @param targetid + * ID of the calling target + * @param actionId + * of the action + * @param request + * the HTTP request injected by spring + * + * @return the {@link DdiCancel} response + */ + @RequestMapping(value = "/{targetid}/" + DdiRestConstants.CANCEL_ACTION + + "/{actionId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + ResponseEntity getControllerCancelAction(@PathVariable("targetid") @NotEmpty final String targetid, + @PathVariable("actionId") @NotEmpty final Long actionId); + + /** + * RequestMethod.POST method receiving the {@link DdiActionFeedback} from + * the target. + * + * @param feedback + * the {@link DdiActionFeedback} from the target. + * @param targetid + * the ID of the calling target + * @param actionId + * of the action we have feedback for + * @param request + * the HTTP request injected by spring + * + * @return the {@link DdiActionFeedback} response + */ + + @RequestMapping(value = "/{targetid}/" + DdiRestConstants.CANCEL_ACTION + "/{actionId}/" + + DdiRestConstants.FEEDBACK, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) + ResponseEntity postCancelActionFeedback(@Valid @RequestBody final DdiActionFeedback feedback, + @PathVariable("targetid") @NotEmpty final String targetid, + @PathVariable("actionId") @NotEmpty final Long actionId); + +} diff --git a/hawkbit-ddi-dl-api/README.md b/hawkbit-ddi-dl-api/README.md new file mode 100644 index 000000000..703ef2916 --- /dev/null +++ b/hawkbit-ddi-dl-api/README.md @@ -0,0 +1,12 @@ +# Eclipse.IoT hawkBit - DDI Download API + +This module is part of the Direct Device Integration (DDI) API and is used by devices/targets for downloading artifacts through HTTP. + +# Compile + +#### Build hawkbit-ddi-dl-api + +``` +$ cd hawkbit/hawkbit-ddi-dl-api +$ mvn clean install +``` diff --git a/hawkbit-ddi-dl-api/pom.xml b/hawkbit-ddi-dl-api/pom.xml new file mode 100644 index 000000000..704267927 --- /dev/null +++ b/hawkbit-ddi-dl-api/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + org.eclipse.hawkbit + hawkbit-parent + 0.2.0-SNAPSHOT + + hawkbit-ddi-dl-api + hawkBit :: DDI Download Server (DL) API + + + + org.springframework.security + spring-security-web + + + diff --git a/hawkbit-ddi-dl-api/src/main/java/org/eclipse/hawkbit/ddi/dl/rest/api/DdiDlArtifactStoreControllerRestApi.java b/hawkbit-ddi-dl-api/src/main/java/org/eclipse/hawkbit/ddi/dl/rest/api/DdiDlArtifactStoreControllerRestApi.java new file mode 100644 index 000000000..53d5940fe --- /dev/null +++ b/hawkbit-ddi-dl-api/src/main/java/org/eclipse/hawkbit/ddi/dl/rest/api/DdiDlArtifactStoreControllerRestApi.java @@ -0,0 +1,59 @@ +/** + * 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.ddi.dl.rest.api; + +import java.io.InputStream; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.web.bind.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * REST resource handling for artifact download operations. + */ +@RequestMapping(DdiDlRestConstants.ARTIFACTS_V1_REQUEST_MAPPING) +public interface DdiDlArtifactStoreControllerRestApi { + + /** + * Handles GET download request. This could be full or partial download + * request. + * + * @param fileName + * to search for + * @param targetid + * of authenticated target + * + * @return response of the servlet which in case of success is status code + * {@link HttpStatus#OK} or in case of partial download + * {@link HttpStatus#PARTIAL_CONTENT}. + */ + @RequestMapping(method = RequestMethod.GET, value = DdiDlRestConstants.ARTIFACT_DOWNLOAD_BY_FILENAME + + "/{fileName}") + @ResponseBody + public ResponseEntity downloadArtifactByFilename(@PathVariable("fileName") final String fileName, + @AuthenticationPrincipal final String targetid); + + /** + * Handles GET MD5 checksum file download request. + * + * @param fileName + * to search for + * + * @return response of the servlet + */ + @RequestMapping(method = RequestMethod.GET, value = DdiDlRestConstants.ARTIFACT_DOWNLOAD_BY_FILENAME + "/{fileName}" + + DdiDlRestConstants.ARTIFACT_MD5_DWNL_SUFFIX) + @ResponseBody + public ResponseEntity downloadArtifactMD5ByFilename(@PathVariable("fileName") final String fileName); + +} diff --git a/hawkbit-ddi-dl-api/src/main/java/org/eclipse/hawkbit/ddi/dl/rest/api/DdiDlRestConstants.java b/hawkbit-ddi-dl-api/src/main/java/org/eclipse/hawkbit/ddi/dl/rest/api/DdiDlRestConstants.java new file mode 100644 index 000000000..40ba5050f --- /dev/null +++ b/hawkbit-ddi-dl-api/src/main/java/org/eclipse/hawkbit/ddi/dl/rest/api/DdiDlRestConstants.java @@ -0,0 +1,40 @@ +/** + * 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.ddi.dl.rest.api; + +/** + * Constants for the direct device integration rest resources. + */ +public final class DdiDlRestConstants { + + /** + * The base URL mapping of the artifact repository rest resources. + */ + public static final String ARTIFACTS_V1_REQUEST_MAPPING = "/{tenant}/controller/artifacts/v1"; + + /** + * The artifact URL mapping rest resource. + */ + public static final String ARTIFACT_DOWNLOAD = "artifact"; + + /** + * The artifact by filename URL mapping rest resource. + */ + public static final String ARTIFACT_DOWNLOAD_BY_FILENAME = "/filename"; + + /** + * File suffix for MDH hash download (see Linux md5sum). + */ + public static final String ARTIFACT_MD5_DWNL_SUFFIX = ".MD5SUM"; + + // constant class, private constructor. + private DdiDlRestConstants() { + + } +} diff --git a/hawkbit-ddi-resource/README.md b/hawkbit-ddi-resource/README.md new file mode 100644 index 000000000..3cfb443cd --- /dev/null +++ b/hawkbit-ddi-resource/README.md @@ -0,0 +1,13 @@ +# Eclipse.IoT hawkBit - DDI Resource + +This is the server-side implementation of the hawkBit DDI API and the hawkBit DDI Download API that is used by devices for communicating with the HawkBit Update Server through HTTP. + +# Compile + +#### Build hawkbit-ddi-resource + +``` +$ cd hawkbit/hawkbit-ddi-resource +$ mvn clean install +``` + diff --git a/hawkbit-ddi-resource/pom.xml b/hawkbit-ddi-resource/pom.xml new file mode 100644 index 000000000..cb85f8c8c --- /dev/null +++ b/hawkbit-ddi-resource/pom.xml @@ -0,0 +1,175 @@ + + + + 4.0.0 + + org.eclipse.hawkbit + hawkbit-parent + 0.2.0-SNAPSHOT + + hawkbit-ddi-resource + hawkBit :: DDI Resources + + + + org.eclipse.hawkbit + hawkbit-ddi-api + ${project.version} + + + org.eclipse.hawkbit + hawkbit-ddi-dl-api + ${project.version} + + + org.eclipse.hawkbit + hawkbit-rest-core + ${project.version} + + + org.eclipse.hawkbit + hawkbit-repository-api + ${project.version} + + + org.springframework.plugin + spring-plugin-core + + + + + + org.eclipse.hawkbit + hawkbit-repository-test + ${project.version} + test + + + org.eclipse.hawkbit + hawkbit-repository-jpa + ${project.version} + test + + + org.eclipse.hawkbit + hawkbit-rest-core + ${project.version} + tests + test + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-logging + + + test + + + org.springframework.boot + spring-boot-starter-log4j2 + test + + + com.h2database + h2 + test + + + org.mariadb.jdbc + mariadb-java-client + test + + + javax.el + javax.el-api + test + + + org.springframework.security + spring-security-config + test + + + org.eclipse.hawkbit + hawkbit-repository-jpa + ${project.version} + tests + test + + + org.eclipse.hawkbit + hawkbit-http-security + ${project.version} + test + + + com.jayway.jsonpath + json-path + test + + + org.json + json + test + + + com.fasterxml.jackson.core + jackson-databind + test + + + com.fasterxml.jackson.core + jackson-core + test + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-aspects + test + + + org.easytesting + fest-assert-core + test + + + org.easytesting + fest-assert + test + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + test + + + ru.yandex.qatools.allure + allure-junit-adaptor + test + + + org.springframework + spring-context-support + test + + + diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/EnableDirectDeviceApi.java b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/EnableDdiApi.java similarity index 80% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/EnableDirectDeviceApi.java rename to hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/EnableDdiApi.java index 846e1e8d2..d9572166a 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/EnableDirectDeviceApi.java +++ b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/EnableDdiApi.java @@ -6,28 +6,28 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller; +package org.eclipse.hawkbit.ddi; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.eclipse.hawkbit.rest.configuration.RestConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.stereotype.Controller; /** * Annotation to enable {@link ComponentScan} in the resource package to setup * all {@link Controller} annotated classes and setup the Direct Device API. - * - * - * */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Configuration @ComponentScan -public @interface EnableDirectDeviceApi { +@Import(RestConfiguration.class) +public @interface EnableDdiApi { } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DataConversionHelper.java similarity index 63% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java rename to hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DataConversionHelper.java index 15c2592df..d87de67d0 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java +++ b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DataConversionHelper.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller; +package org.eclipse.hawkbit.ddi.rest.resource; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; @@ -20,23 +20,25 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.hawkbit.api.ArtifactUrlHandler; import org.eclipse.hawkbit.api.UrlProtocol; -import org.eclipse.hawkbit.controller.model.Artifact; -import org.eclipse.hawkbit.controller.model.Chunk; -import org.eclipse.hawkbit.controller.model.Config; -import org.eclipse.hawkbit.controller.model.ControllerBase; -import org.eclipse.hawkbit.controller.model.Polling; +import org.eclipse.hawkbit.ddi.dl.rest.api.DdiDlRestConstants; +import org.eclipse.hawkbit.ddi.json.model.DdiArtifact; +import org.eclipse.hawkbit.ddi.json.model.DdiArtifactHash; +import org.eclipse.hawkbit.ddi.json.model.DdiChunk; +import org.eclipse.hawkbit.ddi.json.model.DdiConfig; +import org.eclipse.hawkbit.ddi.json.model.DdiControllerBase; +import org.eclipse.hawkbit.ddi.json.model.DdiPolling; +import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; 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.hateoas.Link; import com.google.common.base.Charsets; /** - * Utility class for the Controller API. + * Utility class for the DDI API. */ public final class DataConversionHelper { // utility class, private constructor. @@ -44,12 +46,13 @@ public final class DataConversionHelper { } - static List createChunks(final String targetid, final Action uAction, + static List createChunks(final String targetid, final Action uAction, final ArtifactUrlHandler artifactUrlHandler) { return uAction.getDistributionSet().getModules().stream() - .map(module -> new Chunk(mapChunkLegacyKeys(module.getType().getKey()), module.getVersion(), + .map(module -> new DdiChunk(mapChunkLegacyKeys(module.getType().getKey()), module.getVersion(), module.getName(), createArtifacts(targetid, module, artifactUrlHandler))) .collect(Collectors.toList()); + } private static String mapChunkLegacyKeys(final String key) { @@ -70,22 +73,22 @@ 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, + public static List createArtifacts(final String targetid, final org.eclipse.hawkbit.repository.model.SoftwareModule module, final ArtifactUrlHandler artifactUrlHandler) { - final List files = new ArrayList<>(); + final List files = new ArrayList<>(); + module.getLocalArtifacts() .forEach(artifact -> files.add(createArtifact(targetid, artifactUrlHandler, artifact))); return files; } - private static Artifact createArtifact(final String targetid, final ArtifactUrlHandler artifactUrlHandler, + private static DdiArtifact createArtifact(final String targetid, final ArtifactUrlHandler artifactUrlHandler, final LocalArtifact artifact) { - final Artifact file = new Artifact(); - file.setHashes(new ArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash())); + final DdiArtifact file = new DdiArtifact(); + file.setHashes(new DdiArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash())); file.setFilename(artifact.getFilename()); file.setSize(artifact.getSize()); @@ -93,21 +96,22 @@ public final class DataConversionHelper { 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")); + file.add(new Link(linkHttp + DdiDlRestConstants.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(linkHttps + DdiDlRestConstants.ARTIFACT_MD5_DWNL_SUFFIX).withRel("md5sum")); } return file; } - static ControllerBase fromTarget(final Target target, final List actions, + static DdiControllerBase fromTarget(final Target target, final List actions, final String defaultControllerPollTime, final TenantAware tenantAware) { - final ControllerBase result = new ControllerBase(new Config(new Polling(defaultControllerPollTime))); + final DdiControllerBase result = new DdiControllerBase( + new DdiConfig(new DdiPolling(defaultControllerPollTime))); boolean addedUpdate = false; boolean addedCancel = false; @@ -119,25 +123,41 @@ public final class DataConversionHelper { // have changed from 'soft' to 'forced' type and we need to // change the payload of the // response because of eTags. - result.add(linkTo(methodOn(RootController.class, tenantAware.getCurrentTenant()) - .getControllerBasedeploymentAction(target.getControllerId(), action.getId(), actions.hashCode(), - null)).withRel(ControllerConstants.DEPLOYMENT_BASE_ACTION)); + result.add(linkTo(methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) + .getControllerBasedeploymentAction(target.getControllerId(), action.getId(), + calculateEtag(action))).withRel(DdiRestConstants.DEPLOYMENT_BASE_ACTION)); addedUpdate = true; } else if (action.isCancelingOrCanceled() && !addedCancel) { - result.add(linkTo(methodOn(RootController.class, tenantAware.getCurrentTenant()) - .getControllerCancelAction(target.getControllerId(), action.getId(), null)) - .withRel(ControllerConstants.CANCEL_ACTION)); + result.add(linkTo(methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) + .getControllerCancelAction(target.getControllerId(), action.getId())) + .withRel(DdiRestConstants.CANCEL_ACTION)); addedCancel = true; } } if (target.getTargetInfo().isRequestControllerAttributes()) { - result.add(linkTo(methodOn(RootController.class, tenantAware.getCurrentTenant()).putConfigData(null, - target.getControllerId(), null)).withRel(ControllerConstants.CONFIG_DATA_ACTION)); + result.add(linkTo(methodOn(DdiRootController.class, tenantAware.getCurrentTenant()).putConfigData(null, + target.getControllerId())).withRel(DdiRestConstants.CONFIG_DATA_ACTION)); } return result; } + /** + * Calculates an etag for the given {@link Action} based on the entities + * hashcode and the {@link Action#isHitAutoForceTime(long)} to reflect a + * force switch. + * + * @param action + * to calculate the etag for + * @return the etag + */ + private static int calculateEtag(final Action action) { + final int prime = 31; + int result = action.hashCode(); + result = prime * result + (action.isHitAutoForceTime(System.currentTimeMillis()) ? 1231 : 1237); + return result; + } + static void writeMD5FileResponse(final String fileName, final HttpServletResponse response, final LocalArtifact artifact) throws IOException { final StringBuilder builder = new StringBuilder(); @@ -149,7 +169,7 @@ public final class DataConversionHelper { final StringBuilder header = new StringBuilder(); header.append("attachment;filename="); header.append(fileName); - header.append(ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX); + header.append(DdiDlRestConstants.ARTIFACT_MD5_DWNL_SUFFIX); response.setContentLength(content.length); response.setHeader("Content-Disposition", header.toString()); diff --git a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactStoreController.java b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactStoreController.java new file mode 100644 index 000000000..e2af0a873 --- /dev/null +++ b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactStoreController.java @@ -0,0 +1,159 @@ +/** + * 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.ddi.rest.resource; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; +import org.eclipse.hawkbit.ddi.dl.rest.api.DdiDlArtifactStoreControllerRestApi; +import org.eclipse.hawkbit.repository.ArtifactManagement; +import org.eclipse.hawkbit.repository.ControllerManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.RepositoryConstants; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder; +import org.eclipse.hawkbit.rest.util.RestResourceConversionHelper; +import org.eclipse.hawkbit.security.HawkbitSecurityProperties; +import org.eclipse.hawkbit.util.IpUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.web.bind.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.WebApplicationContext; + +/** + * The {@link DdiArtifactStoreController} of the HawkBit server controller API + * that is queried by the HawkBit target in order to download artifacts + * independent of their own individual resource. This is offered in addition to + * the {@link DdiRootController#downloadArtifact(String, Long, String)} for + * legacy controllers that can not be fed with a download URI at runtime. + */ +@RestController +@Scope(WebApplicationContext.SCOPE_REQUEST) +public class DdiArtifactStoreController implements DdiDlArtifactStoreControllerRestApi { + + private static final Logger LOG = LoggerFactory.getLogger(DdiArtifactStoreController.class); + + @Autowired + private ArtifactManagement artifactManagement; + + @Autowired + private ControllerManagement controllerManagement; + + @Autowired + private HawkbitSecurityProperties securityProperties; + + @Autowired + private RequestResponseContextHolder requestResponseContextHolder; + + @Autowired + private EntityFactory entityFactory; + + @Override + public ResponseEntity downloadArtifactByFilename(@PathVariable("fileName") final String fileName, + @AuthenticationPrincipal final String targetid) { + final List foundArtifacts = artifactManagement.findLocalArtifactByFilename(fileName); + + if (foundArtifacts.isEmpty()) { + LOG.warn("Software artifact with name {} could not be found.", fileName); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + if (foundArtifacts.size() > 1) { + LOG.warn("Software artifact name {} is not unique. We will use the first entry.", fileName); + } + ResponseEntity result; + final LocalArtifact artifact = foundArtifacts.get(0); + + final String ifMatch = requestResponseContextHolder.getHttpServletRequest().getHeader("If-Match"); + if (ifMatch != null && !RestResourceConversionHelper.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) { + result = new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED); + } else { + final DbArtifact file = artifactManagement.loadLocalArtifactBinary(artifact); + + // we set a download status only if we are aware of the + // targetid, i.e. authenticated and not anonymous + if (targetid != null && !"anonymous".equals(targetid)) { + final ActionStatus actionStatus = checkAndReportDownloadByTarget( + requestResponseContextHolder.getHttpServletRequest(), targetid, artifact); + result = RestResourceConversionHelper.writeFileResponse(artifact, + requestResponseContextHolder.getHttpServletResponse(), + requestResponseContextHolder.getHttpServletRequest(), file, controllerManagement, + actionStatus.getId()); + } else { + result = RestResourceConversionHelper.writeFileResponse(artifact, + requestResponseContextHolder.getHttpServletResponse(), + requestResponseContextHolder.getHttpServletRequest(), file); + } + + } + return result; + } + + @Override + public ResponseEntity downloadArtifactMD5ByFilename(@PathVariable("fileName") final String fileName) { + final List foundArtifacts = artifactManagement.findLocalArtifactByFilename(fileName); + + if (foundArtifacts.isEmpty()) { + LOG.warn("Softeare artifact with name {} could not be found.", fileName); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } else if (foundArtifacts.size() > 1) { + LOG.error("Softeare artifact name {} is not unique.", fileName); + } + + try { + DataConversionHelper.writeMD5FileResponse(fileName, requestResponseContextHolder.getHttpServletResponse(), + foundArtifacts.get(0)); + } catch (final IOException e) { + LOG.error("Failed to stream MD5 File", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + + return new ResponseEntity<>(HttpStatus.OK); + } + + private ActionStatus checkAndReportDownloadByTarget(final HttpServletRequest request, final String targetid, + final LocalArtifact artifact) { + final Target target = controllerManagement.updateLastTargetQuery(targetid, + IpUtil.getClientIpFromRequest(request, securityProperties)); + + final Action action = controllerManagement + .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), artifact.getSoftwareModule()); + final String range = request.getHeader("Range"); + + final ActionStatus actionStatus = entityFactory.generateActionStatus(); + actionStatus.setAction(action); + actionStatus.setOccurredAt(System.currentTimeMillis()); + actionStatus.setStatus(Status.DOWNLOAD); + + if (range != null) { + actionStatus.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + + " of: " + request.getRequestURI()); + } else { + actionStatus.addMessage( + RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads: " + request.getRequestURI()); + } + + return controllerManagement.addInformationalActionStatus(actionStatus); + } + +} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java similarity index 52% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java rename to hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java index 3969e1b83..9dd65d5fc 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java +++ b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java @@ -6,41 +6,43 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller; +package org.eclipse.hawkbit.ddi.rest.resource; import java.io.IOException; +import java.io.InputStream; import java.util.List; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import org.eclipse.hawkbit.api.ArtifactUrlHandler; import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; -import org.eclipse.hawkbit.cache.CacheWriteNotify; -import org.eclipse.hawkbit.controller.model.ActionFeedback; -import org.eclipse.hawkbit.controller.model.Cancel; -import org.eclipse.hawkbit.controller.model.CancelActionToStop; -import org.eclipse.hawkbit.controller.model.Chunk; -import org.eclipse.hawkbit.controller.model.ConfigData; -import org.eclipse.hawkbit.controller.model.ControllerBase; -import org.eclipse.hawkbit.controller.model.Deployment; -import org.eclipse.hawkbit.controller.model.Deployment.HandlingType; -import org.eclipse.hawkbit.controller.model.DeploymentBase; -import org.eclipse.hawkbit.controller.model.Result.FinalResult; +import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback; +import org.eclipse.hawkbit.ddi.json.model.DdiCancel; +import org.eclipse.hawkbit.ddi.json.model.DdiCancelActionToStop; +import org.eclipse.hawkbit.ddi.json.model.DdiChunk; +import org.eclipse.hawkbit.ddi.json.model.DdiConfigData; +import org.eclipse.hawkbit.ddi.json.model.DdiControllerBase; +import org.eclipse.hawkbit.ddi.json.model.DdiDeployment; +import org.eclipse.hawkbit.ddi.json.model.DdiDeployment.HandlingType; +import org.eclipse.hawkbit.ddi.json.model.DdiDeploymentBase; +import org.eclipse.hawkbit.ddi.json.model.DdiResult.FinalResult; +import org.eclipse.hawkbit.ddi.rest.api.DdiRootControllerRestApi; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ControllerManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.ActionStatus; -import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper; +import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder; +import org.eclipse.hawkbit.rest.util.RestResourceConversionHelper; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.util.IpUtil; @@ -48,29 +50,27 @@ import org.hibernate.validator.constraints.NotEmpty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.WebApplicationContext; /** - * The {@link RootController} of the SP server controller API that is queried by - * the SP controller in order to pull {@link Action}s that have to be fullfilled - * and report status updates concerning the {@link Action} processing. + * The {@link DdiRootController} of the hawkBit server DDI API that is queried + * by the hawkBit controller in order to pull {@link Action}s that have to be + * fulfilled and report status updates concerning the {@link Action} processing. * * Transactional (read-write) as all queries at least update the last poll time. - * */ @RestController -@RequestMapping(ControllerConstants.BASE_V1_REQUEST_MAPPING) -public class RootController { +@Scope(value = WebApplicationContext.SCOPE_REQUEST) +public class DdiRootController implements DdiRootControllerRestApi { - private static final Logger LOG = LoggerFactory.getLogger(RootController.class); + private static final Logger LOG = LoggerFactory.getLogger(DdiRootController.class); private static final String GIVEN_ACTION_IS_NOT_ASSIGNED_TO_GIVEN_TARGET = "given action ({}) is not assigned to given target ({})."; @Autowired @@ -82,9 +82,6 @@ public class RootController { @Autowired private ArtifactManagement artifactManagement; - @Autowired - private CacheWriteNotify cacheWriteNotify; - @Autowired private HawkbitSecurityProperties securityProperties; @@ -94,20 +91,16 @@ public class RootController { @Autowired private ArtifactUrlHandler artifactUrlHandler; - /** - * Returns all artifacts of a given software module and target. - * - * @param targetid - * of the {@link Target} that matches to - * {@link Target#getControllerId()} - * @param softwareModuleId - * of the {@link SoftwareModule} - * @return the response - */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts", produces = { - "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getSoftwareModulesArtifacts( - @PathVariable final String targetid, @PathVariable final Long softwareModuleId) { + @Autowired + private RequestResponseContextHolder requestResponseContextHolder; + + @Autowired + private EntityFactory entityFactory; + + @Override + public ResponseEntity> getSoftwareModulesArtifacts( + @PathVariable("targetid") final String targetid, + @PathVariable("softwareModuleId") final Long softwareModuleId) { LOG.debug("getSoftwareModulesArtifacts({})", targetid); final SoftwareModule softwareModule = softwareManagement.findSoftwareModuleById(softwareModuleId); @@ -122,65 +115,34 @@ public class RootController { HttpStatus.OK); } - /** - * Root resource for an individual {@link Target}. - * - * @param targetid - * of the {@link Target} that matches to - * {@link Target#getControllerId()} - * @param request - * the HTTP request injected by spring - * @return the response - */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetid}", produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getControllerBase(@PathVariable final String targetid, - final HttpServletRequest request) { + @Override + public ResponseEntity getControllerBase(@PathVariable("targetid") final String targetid) { LOG.debug("getControllerBase({})", targetid); - final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(targetid, - IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); if (target.getTargetInfo().getUpdateStatus() == TargetUpdateStatus.UNKNOWN) { LOG.debug("target with {} extsisted but was in status UNKNOWN -> REGISTERED)", targetid); controllerManagement.updateTargetStatus(target.getTargetInfo(), TargetUpdateStatus.REGISTERED, - System.currentTimeMillis(), - IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader())); + System.currentTimeMillis(), IpUtil.getClientIpFromRequest( + requestResponseContextHolder.getHttpServletRequest(), securityProperties)); } return new ResponseEntity<>( DataConversionHelper.fromTarget(target, controllerManagement.findActionByTargetAndActive(target), - controllerManagement.findPollingTime(), tenantAware), + controllerManagement.getPollingTime(), tenantAware), HttpStatus.OK); } - /** - * Handles GET {@link Artifact} download request. This could be full or - * partial (as specified by RFC7233 (Range Requests)) download request. - * - * @param targetid - * of the related - * @param softwareModuleId - * of the parent {@link SoftwareModule} - * @param fileName - * of the related {@link LocalArtifact} - * @param response - * of the servlet - * @param request - * from the client - * - * @return response of the servlet which in case of success is status code - * {@link HttpStatus#OK} or in case of partial download - * {@link HttpStatus#PARTIAL_CONTENT}. - */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{fileName}") - public ResponseEntity downloadArtifact(@PathVariable final String targetid, - @PathVariable final Long softwareModuleId, @PathVariable final String fileName, - final HttpServletResponse response, final HttpServletRequest request) { - ResponseEntity result; + @Override + public ResponseEntity downloadArtifact(@PathVariable("targetid") final String targetid, + @PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("fileName") final String fileName) { + ResponseEntity result; - final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId); if (checkModule(fileName, module)) { @@ -190,70 +152,53 @@ public class RootController { final LocalArtifact artifact = module.getLocalArtifactByFilename(fileName).get(); final DbArtifact file = artifactManagement.loadLocalArtifactBinary(artifact); - final String ifMatch = request.getHeader("If-Match"); + final String ifMatch = requestResponseContextHolder.getHttpServletRequest().getHeader("If-Match"); if (ifMatch != null && !RestResourceConversionHelper.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) { result = new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED); } else { - final Action action = checkAndLogDownload(request, target, module); - result = RestResourceConversionHelper.writeFileResponse(artifact, response, request, file, - cacheWriteNotify, action.getId()); + final ActionStatus action = checkAndLogDownload(requestResponseContextHolder.getHttpServletRequest(), + target, module); + result = RestResourceConversionHelper.writeFileResponse(artifact, + requestResponseContextHolder.getHttpServletResponse(), + requestResponseContextHolder.getHttpServletRequest(), file, controllerManagement, + action.getId()); } - } - return result; } - private Action checkAndLogDownload(final HttpServletRequest request, final Target target, + private ActionStatus checkAndLogDownload(final HttpServletRequest request, final Target target, final SoftwareModule module) { final Action action = controllerManagement .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), module); final String range = request.getHeader("Range"); - final ActionStatus statusMessage = new ActionStatus(); + final ActionStatus statusMessage = entityFactory.generateActionStatus(); statusMessage.setAction(action); statusMessage.setOccurredAt(System.currentTimeMillis()); statusMessage.setStatus(Status.DOWNLOAD); if (range != null) { - statusMessage.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + statusMessage.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + " of: " + request.getRequestURI()); } else { statusMessage.addMessage( - ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads " + request.getRequestURI()); + RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads " + request.getRequestURI()); } - controllerManagement.addActionStatusMessage(statusMessage); - return action; + + return controllerManagement.addInformationalActionStatus(statusMessage); } private static boolean checkModule(final String fileName, final SoftwareModule module) { return null == module || !module.getLocalArtifactByFilename(fileName).isPresent(); } - /** - * Handles GET {@link Artifact} MD5 checksum file download request. - * - * @param targetid - * of the related - * @param softwareModuleId - * of the parent {@link SoftwareModule} - * @param fileName - * of the related {@link LocalArtifact} - * @param response - * of the servlet - * @param request - * the HTTP request injected by spring - * - * @return {@link ResponseEntity} with status {@link HttpStatus#OK} if - * successful - */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{fileName}" - + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX, produces = MediaType.TEXT_PLAIN_VALUE) - public ResponseEntity downloadArtifactMd5(@PathVariable final String targetid, - @PathVariable final Long softwareModuleId, @PathVariable final String fileName, - final HttpServletResponse response, final HttpServletRequest request) { - controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader())); + @Override + public ResponseEntity downloadArtifactMd5(@PathVariable("targetid") final String targetid, + @PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("fileName") final String fileName) { + controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId); @@ -263,7 +208,7 @@ public class RootController { } try { - DataConversionHelper.writeMD5FileResponse(fileName, response, + DataConversionHelper.writeMD5FileResponse(fileName, requestResponseContextHolder.getHttpServletResponse(), module.getLocalArtifactByFilename(fileName).get()); } catch (final IOException e) { LOG.error("Failed to stream MD5 File", e); @@ -273,33 +218,14 @@ public class RootController { return new ResponseEntity<>(HttpStatus.OK); } - /** - * Resource for {@link SoftwareModule} {@link UpdateAction}s. - * - * @param targetid - * of the {@link Target} that matches to - * {@link Target#getControllerId()} - * @param actionId - * of the {@link DeploymentBase} that matches to - * {@link Target#getActiveActions()} - * @param resource - * an hashcode of the resource which indicates if the action has - * been changed, e.g. from 'soft' to 'force' and the eTag needs - * to be re-generated - * @param request - * the HTTP request injected by spring - * @return the response - */ - @RequestMapping(value = "/{targetid}/" + ControllerConstants.DEPLOYMENT_BASE_ACTION - + "/{actionId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity getControllerBasedeploymentAction( - @PathVariable @NotEmpty final String targetid, @PathVariable @NotEmpty final Long actionId, - @RequestParam(value = "c", required = false, defaultValue = "-1") final int resource, - final HttpServletRequest request) { + @Override + public ResponseEntity getControllerBasedeploymentAction( + @PathVariable("targetid") final String targetid, @PathVariable("actionId") final Long actionId, + @RequestParam(value = "c", required = false, defaultValue = "-1") final int resource) { LOG.debug("getControllerBasedeploymentAction({},{})", targetid, resource); - final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); final Action action = findActionWithExceptionIfNotFound(actionId); if (!action.getTarget().getId().equals(target.getId())) { @@ -309,16 +235,16 @@ public class RootController { if (!action.isCancelingOrCanceled()) { - final List chunks = DataConversionHelper.createChunks(targetid, action, artifactUrlHandler); + final List chunks = DataConversionHelper.createChunks(targetid, action, artifactUrlHandler); final HandlingType handlingType = action.isForce() ? HandlingType.FORCED : HandlingType.ATTEMPT; - final DeploymentBase base = new DeploymentBase(Long.toString(action.getId()), - new Deployment(handlingType, handlingType, chunks)); + final DdiDeploymentBase base = new DdiDeploymentBase(Long.toString(action.getId()), + new DdiDeployment(handlingType, handlingType, chunks)); LOG.debug("Found an active UpdateAction for target {}. returning deyploment: {}", targetid, base); - controllerManagement.registerRetrieved(action, ControllerManagement.SERVER_MESSAGE_PREFIX + controllerManagement.registerRetrieved(action, RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target retrieved update action and should start now the download."); return new ResponseEntity<>(base, HttpStatus.OK); @@ -327,30 +253,13 @@ public class RootController { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } - /** - * This is the feedback channel for the {@link DeploymentBase} action. - * - * @param feedback - * to provide - * @param targetid - * of the {@link Target} that matches to - * {@link Target#getControllerId()} - * @param actionId - * of the action we have feedback for - * @param request - * the HTTP request injected by spring - * - * @return the response - */ - @RequestMapping(value = "/{targetid}/" + ControllerConstants.DEPLOYMENT_BASE_ACTION + "/{actionId}/" - + ControllerConstants.FEEDBACK, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity postBasedeploymentActionFeedback(@Valid @RequestBody final ActionFeedback feedback, - @PathVariable final String targetid, @PathVariable @NotEmpty final Long actionId, - final HttpServletRequest request) { + @Override + public ResponseEntity postBasedeploymentActionFeedback(@Valid @RequestBody final DdiActionFeedback feedback, + @PathVariable("targetid") final String targetid, @PathVariable("actionId") @NotEmpty final Long actionId) { LOG.debug("provideBasedeploymentActionFeedback for target [{},{}]: {}", targetid, actionId, feedback); - final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); if (!actionId.equals(feedback.getId())) { LOG.warn( @@ -371,17 +280,16 @@ public class RootController { return new ResponseEntity<>(HttpStatus.GONE); } - controllerManagement.addUpdateActionStatus(generateUpdateStatus(feedback, targetid, feedback.getId(), action), - action); + controllerManagement.addUpdateActionStatus(generateUpdateStatus(feedback, targetid, feedback.getId(), action)); return new ResponseEntity<>(HttpStatus.OK); } - private ActionStatus generateUpdateStatus(final ActionFeedback feedback, final String targetid, final Long actionid, - final Action action) { + private ActionStatus generateUpdateStatus(final DdiActionFeedback feedback, final String targetid, + final Long actionid, final Action action) { - final ActionStatus actionStatus = new ActionStatus(); + final ActionStatus actionStatus = entityFactory.generateActionStatus(); actionStatus.setAction(action); actionStatus.setOccurredAt(System.currentTimeMillis()); @@ -390,13 +298,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(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target confirmed cancelation."); + actionStatus.addMessage(RepositoryConstants.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(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target REJECTED update."); + actionStatus.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target REJECTED update."); break; case CLOSED: handleClosedUpdateStatus(feedback, targetid, actionid, actionStatus); @@ -418,72 +326,47 @@ public class RootController { return actionStatus; } - private static void handleDefaultUpdateStatus(final ActionFeedback feedback, final String targetid, + private static void handleDefaultUpdateStatus(final DdiActionFeedback feedback, final String targetid, final Long actionid, final ActionStatus actionStatus) { LOG.debug("Controller reported intermediate status (actionid: {}, targetid: {}) as we got {} report.", actionid, targetid, feedback.getStatus().getExecution()); actionStatus.setStatus(Status.RUNNING); actionStatus.addMessage( - ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported " + feedback.getStatus().getExecution()); + RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target reported " + feedback.getStatus().getExecution()); } - private static void handleClosedUpdateStatus(final ActionFeedback feedback, final String targetid, + private static void handleClosedUpdateStatus(final DdiActionFeedback feedback, final String targetid, final Long actionid, final ActionStatus actionStatus) { LOG.debug("Controller reported closed (actionid: {}, targetid: {}) as we got {} report.", actionid, targetid, feedback.getStatus().getExecution()); if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) { actionStatus.setStatus(Status.ERROR); - actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported CLOSED with ERROR!"); + actionStatus.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target reported CLOSED with ERROR!"); } else { actionStatus.setStatus(Status.FINISHED); - actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported CLOSED with OK!"); + actionStatus.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target reported CLOSED with OK!"); } } - /** - * This is the feedback channel for the config data action. - * - * @param configData - * as body - * @param targetid - * to provide data for - * @param request - * the HTTP request injected by spring - * - * @return status of the request - */ - @RequestMapping(value = "/{targetid}/" - + ControllerConstants.CONFIG_DATA_ACTION, method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity putConfigData(@Valid @RequestBody final ConfigData configData, - @PathVariable final String targetid, final HttpServletRequest request) { - controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader())); + @Override + public ResponseEntity putConfigData(@Valid @RequestBody final DdiConfigData configData, + @PathVariable("targetid") final String targetid) { + controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); controllerManagement.updateControllerAttributes(targetid, configData.getData()); return new ResponseEntity<>(HttpStatus.OK); } - /** - * {@link RequestMethod.GET} method for the {@link Cancel} action. - * - * @param targetid - * ID of the calling target - * @param actionId - * of the action - * @param request - * the HTTP request injected by spring - * - * @return the {@link Cancel} response - */ - @RequestMapping(value = "/{targetid}/" + ControllerConstants.CANCEL_ACTION - + "/{actionId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity getControllerCancelAction(@PathVariable @NotEmpty final String targetid, - @PathVariable @NotEmpty final Long actionId, final HttpServletRequest request) { + @Override + public ResponseEntity getControllerCancelAction( + @PathVariable("targetid") @NotEmpty final String targetid, + @PathVariable("actionId") @NotEmpty final Long actionId) { LOG.debug("getControllerCancelAction({})", targetid); - final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); final Action action = findActionWithExceptionIfNotFound(actionId); if (!action.getTarget().getId().equals(target.getId())) { @@ -492,12 +375,12 @@ public class RootController { } if (action.isCancelingOrCanceled()) { - final Cancel cancel = new Cancel(String.valueOf(action.getId()), - new CancelActionToStop(String.valueOf(action.getId()))); + final DdiCancel cancel = new DdiCancel(String.valueOf(action.getId()), + new DdiCancelActionToStop(String.valueOf(action.getId()))); LOG.debug("Found an active CancelAction for target {}. returning cancel: {}", targetid, cancel); - controllerManagement.registerRetrieved(action, ControllerManagement.SERVER_MESSAGE_PREFIX + controllerManagement.registerRetrieved(action, RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target retrieved cancel action and should start now the cancelation."); return new ResponseEntity<>(cancel, HttpStatus.OK); @@ -506,31 +389,14 @@ public class RootController { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } - /** - * {@link RequestMethod.POST} method receiving the {@link ActionFeedback} - * from the target. - * - * @param feedback - * the {@link ActionFeedback} from the target. - * @param targetid - * the ID of the calling target - * @param actionId - * of the action we have feedback for - * @param request - * the HTTP request injected by spring - * - * @return the {@link ActionFeedback} response - */ - - @RequestMapping(value = "/{targetid}/" + ControllerConstants.CANCEL_ACTION + "/{actionId}/" - + ControllerConstants.FEEDBACK, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity postCancelActionFeedback(@Valid @RequestBody final ActionFeedback feedback, - @PathVariable @NotEmpty final String targetid, @PathVariable @NotEmpty final Long actionId, - final HttpServletRequest request) { + @Override + public ResponseEntity postCancelActionFeedback(@Valid @RequestBody final DdiActionFeedback feedback, + @PathVariable("targetid") @NotEmpty final String targetid, + @PathVariable("actionId") @NotEmpty final Long actionId) { LOG.debug("provideCancelActionFeedback for target [{}]: {}", targetid, feedback); - final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); if (!actionId.equals(feedback.getId())) { LOG.warn( @@ -545,15 +411,15 @@ public class RootController { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } - controllerManagement - .addCancelActionStatus(generateActionCancelStatus(feedback, target, feedback.getId(), action), action); + controllerManagement.addCancelActionStatus( + generateActionCancelStatus(feedback, target, feedback.getId(), action, entityFactory)); return new ResponseEntity<>(HttpStatus.OK); } - private static ActionStatus generateActionCancelStatus(final ActionFeedback feedback, final Target target, - final Long actionid, final Action action) { + private static ActionStatus generateActionCancelStatus(final DdiActionFeedback feedback, final Target target, + final Long actionid, final Action action, final EntityFactory entityFactory) { - final ActionStatus actionStatus = new ActionStatus(); + final ActionStatus actionStatus = entityFactory.generateActionStatus(); actionStatus.setAction(action); actionStatus.setOccurredAt(System.currentTimeMillis()); @@ -590,7 +456,7 @@ public class RootController { } - private static void handleClosedCancelStatus(final ActionFeedback feedback, final ActionStatus actionStatus) { + private static void handleClosedCancelStatus(final DdiActionFeedback feedback, final ActionStatus actionStatus) { if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) { actionStatus.setStatus(Status.ERROR); } else { @@ -605,5 +471,4 @@ public class RootController { } return findAction; } - } diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/ArtifactDownloadTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java similarity index 89% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/ArtifactDownloadTest.java rename to hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java index 6149472a7..81be97b7c 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/ArtifactDownloadTest.java +++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller; +package org.eclipse.hawkbit.ddi.rest.resource; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.assertTrue; @@ -26,23 +26,21 @@ import java.util.Arrays; import java.util.List; import org.apache.commons.lang3.RandomUtils; -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.WithUser; -import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.test.util.WithUser; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB; import org.junit.Test; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort.Direction; import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.servlet.MvcResult; import com.google.common.base.Charsets; @@ -56,19 +54,20 @@ import ru.yandex.qatools.allure.annotations.Stories; /** * Test artifact downloads from the controller. - * */ - -@ActiveProfiles({ "im", "test" }) @Features("Component Tests - Direct Device Integration API") @Stories("Artifact Download Resource") -public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { +public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMongoDB { - public ArtifactDownloadTest() { - LOG = LoggerFactory.getLogger(ArtifactDownloadTest.class); + private static final int ARTIFACT_SIZE = 5 * 1024 * 1024; + + public DdiArtifactDownloadTest() { + LOG = LoggerFactory.getLogger(DdiArtifactDownloadTest.class); } private volatile int downLoadProgress = 0; + private volatile long shippedBytes = 0; + private volatile long shippedBytesTotal = 0; @Autowired private EventBus eventBus; @@ -77,14 +76,13 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { @Description("Tests non allowed requests on the artifact ressource, e.g. invalid URI, wrong if-match, wrong command.") public void invalidRequestsOnArtifactResource() throws Exception { // create target - Target target = new Target("4712"); + Target target = entityFactory.generateTarget("4712"); target = targetManagement.createTarget(target); final List targets = new ArrayList<>(); targets.add(target); // create ds - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); deploymentManagement.assignDistributionSet(ds, targets); // create artifact @@ -162,14 +160,13 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { @Description("Tests non allowed requests on the artifact ressource, e.g. invalid URI, wrong if-match, wrong command.") public void invalidRequestsOnArtifactResourceByName() throws Exception { // create target - Target target = new Target("4712"); + Target target = entityFactory.generateTarget("4712"); target = targetManagement.createTarget(target); final List targets = new ArrayList<>(); targets.add(target); // create ds - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); deploymentManagement.assignDistributionSet(ds, targets); // create artifact @@ -243,22 +240,22 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { @Description("Tests valid downloads through the artifact resource by identifying the artifact not by ID but file name.") public void downloadArtifactThroughFileName() throws Exception { downLoadProgress = 1; + shippedBytes = 0; + shippedBytesTotal = 0; eventBus.register(this); assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0); - assertThat(artifactRepository.findAll()).hasSize(0); // create target - Target target = new Target("4712"); + Target target = entityFactory.generateTarget("4712"); target = targetManagement.createTarget(target); final List targets = new ArrayList(); targets.add(target); // create ds - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); // create artifact - final byte random[] = RandomUtils.nextBytes(5 * 1024 * 1024); + final byte random[] = RandomUtils.nextBytes(ARTIFACT_SIZE); final LocalArtifact artifact = artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), ds.findFirstModuleByType(osType).getId(), "file1", false); @@ -285,18 +282,18 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { // download complete assertThat(downLoadProgress).isEqualTo(10); + assertThat(shippedBytes).isEqualTo(shippedBytesTotal).isEqualTo(ARTIFACT_SIZE); } @Test @Description("Tests valid MD5SUm file downloads through the artifact resource by identifying the artifact by ID.") public void downloadMd5sumThroughControllerApi() throws Exception { // create target - Target target = new Target("4712"); + Target target = entityFactory.generateTarget("4712"); target = targetManagement.createTarget(target); // create ds - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); // create artifact final byte random[] = RandomUtils.nextBytes(5 * 1024); @@ -323,30 +320,33 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { + "anonymous as authorization is notpossible, e.g. chekc if the controller has the artifact assigned.") public void downloadArtifactByNameFailsIfNotAuthenticated() throws Exception { downLoadProgress = 1; + shippedBytes = 0; + shippedBytesTotal = 0; eventBus.register(this); assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0); - assertThat(artifactRepository.findAll()).hasSize(0); // create target - Target target = new Target("4712"); + Target target = entityFactory.generateTarget("4712"); target = targetManagement.createTarget(target); - final List targets = new ArrayList(); + final List targets = new ArrayList<>(); targets.add(target); // create ds - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); // create artifact - final byte random[] = RandomUtils.nextBytes(5 * 1024); - final Artifact artifact = artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), + final byte random[] = RandomUtils.nextBytes(ARTIFACT_SIZE); + artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), ds.findFirstModuleByType(osType).getId(), "file1.tar.bz2", false); // download fails as artifact is not yet assigned to target deploymentManagement.assignDistributionSet(ds, targets); mvc.perform(get("/controller/artifacts/v1/filename/{filename}", "file1.tar.bz2")) .andExpect(status().isNotFound()); + + assertThat(downLoadProgress).isEqualTo(1); + assertThat(shippedBytes).isEqualTo(shippedBytesTotal).isEqualTo(0L); } @Test @@ -354,23 +354,23 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { @Description("Ensures that an authenticated and named controller is permitted to download.") public void downloadArtifactByNameByNamedController() throws Exception { downLoadProgress = 1; + shippedBytes = 0; + shippedBytesTotal = 0; eventBus.register(this); assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0); - assertThat(artifactRepository.findAll()).hasSize(0); // create target - Target target = new Target("4712"); + Target target = entityFactory.generateTarget("4712"); target = targetManagement.createTarget(target); final List targets = new ArrayList<>(); targets.add(target); // create ds - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); // create artifact - final byte random[] = RandomUtils.nextBytes(5 * 1024 * 1024); + final byte random[] = RandomUtils.nextBytes(ARTIFACT_SIZE); final Artifact artifact = artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), ds.findFirstModuleByType(osType).getId(), "file1", false); @@ -393,17 +393,17 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { Arrays.equals(result.getResponse().getContentAsByteArray(), random)); // one (update) action - assertThat(actionRepository.findByTargetAndDistributionSet(pageReq, target, ds).getContent()).hasSize(1); - final Action action = actionRepository.findByTargetAndDistributionSet(pageReq, target, ds).getContent().get(0); + assertThat(deploymentManagement.findActionsByTarget(target)).hasSize(1); + final Action action = deploymentManagement.findActionsByTarget(target).get(0); // one status - download - assertThat(actionStatusRepository.findAll()).hasSize(2); - assertThat(actionStatusRepository.findByAction(pageReq, action).getContent()).hasSize(2); - assertThat(actionStatusRepository.findByAction(new PageRequest(0, 400, Direction.DESC, "id"), action) + assertThat(action.getActionStatus()).hasSize(2); + assertThat(deploymentManagement.findActionStatusByAction(new PageRequest(0, 400, Direction.DESC, "id"), action) .getContent().get(0).getStatus()).isEqualTo(Status.DOWNLOAD); // download complete assertThat(downLoadProgress).isEqualTo(10); + assertThat(shippedBytes).isEqualTo(shippedBytesTotal).isEqualTo(ARTIFACT_SIZE); } @Test @@ -411,14 +411,13 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { @Description("Test various HTTP range requests for artifact download, e.g. chunk download or download resume.") public void rangeDownloadArtifactByName() throws Exception { // create target - Target target = new Target("4712"); + Target target = entityFactory.generateTarget("4712"); target = targetManagement.createTarget(target); final List targets = new ArrayList<>(); targets.add(target); // create ds - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); final int resultLength = 5 * 1000 * 1024; @@ -516,17 +515,15 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { @Description("Ensures that the download fails if te controller is not authenticated.") public void faildDownloadArtifactByNameIfAuthenticationMissing() throws Exception { assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0); - assertThat(artifactRepository.findAll()).hasSize(0); // create target - Target target = new Target("4712"); + Target target = entityFactory.generateTarget("4712"); target = targetManagement.createTarget(target); final List targets = new ArrayList<>(); targets.add(target); // create ds - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); // create artifact final byte random[] = RandomUtils.nextBytes(5 * 1024); @@ -542,12 +539,11 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { @Description("Downloads an MD5SUM file by the related artifacts filename.") public void downloadMd5sumFileByName() throws Exception { // create target - Target target = new Target("4712"); + Target target = entityFactory.generateTarget("4712"); target = targetManagement.createTarget(target); // create ds - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); // create artifact final byte random[] = RandomUtils.nextBytes(5 * 1024); @@ -569,5 +565,8 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { @Subscribe public void listen(final DownloadProgressEvent event) { downLoadProgress++; + shippedBytes += event.getShippedBytesSinceLast(); + shippedBytesTotal = event.getShippedBytesOverall(); + } } diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/CancelActionTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiCancelActionTest.java similarity index 91% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/CancelActionTest.java rename to hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiCancelActionTest.java index d7e0351cf..821c8b8ad 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/CancelActionTest.java +++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiCancelActionTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller; +package org.eclipse.hawkbit.ddi.rest.resource; import static org.fest.assertions.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.equalTo; @@ -22,35 +22,34 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.util.ArrayList; import java.util.List; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.rest.resource.JsonBuilder; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; +import org.eclipse.hawkbit.rest.util.JsonBuilder; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.junit.Test; import org.springframework.hateoas.MediaTypes; import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; import ru.yandex.qatools.allure.annotations.Description; import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; -@ActiveProfiles({ "im", "test" }) +/** + * Test cancel action from the controller. + */ @Features("Component Tests - Direct Device Integration API") @Stories("Cancel Action Resource") -public class CancelActionTest extends AbstractIntegrationTest { +public class DdiCancelActionTest extends AbstractRestIntegrationTest { @Test @Description("Test of the controller can continue a started update even after a cancel command if it so desires.") public void rootRsCancelActionButContinueAnyway() throws Exception { // prepare test data - final Target target = new Target("4712"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final Target target = entityFactory.generateTarget("4712"); + final DistributionSet ds = testdataFactory.createDistributionSet(""); final Target savedTarget = targetManagement.createTarget(target); final List toAssign = new ArrayList(); @@ -105,9 +104,8 @@ public class CancelActionTest extends AbstractIntegrationTest { @Test @Description("Test for cancel operation of a update action.") public void rootRsCancelAction() throws Exception { - final Target target = new Target("4712"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final Target target = entityFactory.generateTarget("4712"); + final DistributionSet ds = testdataFactory.createDistributionSet(""); final Target savedTarget = targetManagement.createTarget(target); final List toAssign = new ArrayList(); @@ -223,9 +221,8 @@ public class CancelActionTest extends AbstractIntegrationTest { } private Action createCancelAction(final String targetid) { - final Target target = new Target(targetid); - final DistributionSet ds = TestDataUtil.generateDistributionSet(targetid, softwareManagement, - distributionSetManagement); + final Target target = entityFactory.generateTarget(targetid); + final DistributionSet ds = testdataFactory.createDistributionSet(targetid); final Target savedTarget = targetManagement.createTarget(target); final List toAssign = new ArrayList(); toAssign.add(savedTarget); @@ -240,9 +237,8 @@ public class CancelActionTest extends AbstractIntegrationTest { @Description("Tests the feedback channel of the cancel operation.") public void rootRsCancelActionFeedback() throws Exception { - final Target target = new Target("4712"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final Target target = entityFactory.generateTarget("4712"); + final DistributionSet ds = testdataFactory.createDistributionSet(""); final Target savedTarget = targetManagement.createTarget(target); @@ -252,7 +248,7 @@ public class CancelActionTest extends AbstractIntegrationTest { // cancel action manually final Action cancelAction = deploymentManagement.cancelAction(updateAction, targetManagement.findTargetByControllerID(savedTarget.getControllerId())); - assertThat(actionStatusRepository.findAll()).hasSize(2); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(2); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(1); long current = System.currentTimeMillis(); @@ -265,7 +261,7 @@ public class CancelActionTest extends AbstractIntegrationTest { .isGreaterThanOrEqualTo(current); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(1); - assertThat(actionStatusRepository.findAll()).hasSize(3); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(3); current = System.currentTimeMillis(); mvc.perform(post("/{tenant}/controller/v1/4712/cancelAction/" + cancelAction.getId() + "/feedback", @@ -276,7 +272,7 @@ public class CancelActionTest extends AbstractIntegrationTest { assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getLastTargetQuery()) .isGreaterThanOrEqualTo(current); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(1); - assertThat(actionStatusRepository.findAll()).hasSize(4); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(4); current = System.currentTimeMillis(); mvc.perform(post("/{tenant}/controller/v1/4712/cancelAction/" + cancelAction.getId() + "/feedback", @@ -286,7 +282,7 @@ public class CancelActionTest extends AbstractIntegrationTest { .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getLastTargetQuery()) .isGreaterThanOrEqualTo(current); - assertThat(actionStatusRepository.findAll()).hasSize(5); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(5); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(1); // cancelation canceled -> should remove the action from active @@ -299,7 +295,7 @@ public class CancelActionTest extends AbstractIntegrationTest { .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getLastTargetQuery()) .isGreaterThanOrEqualTo(current); - assertThat(actionStatusRepository.findAll()).hasSize(6); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(6); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(1); // cancelation rejected -> action still active until controller close it @@ -314,7 +310,7 @@ public class CancelActionTest extends AbstractIntegrationTest { .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getLastTargetQuery()) .isGreaterThanOrEqualTo(current); - assertThat(actionStatusRepository.findAll()).hasSize(7); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(7); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(1); // cancelaction closed -> should remove the action from active @@ -326,20 +322,17 @@ public class CancelActionTest extends AbstractIntegrationTest { .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getLastTargetQuery()) .isGreaterThanOrEqualTo(current); - assertThat(actionStatusRepository.findAll()).hasSize(8); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(8); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(0); } @Test @Description("Tests the feeback chanel of for multiple open cancel operations on the same target.") public void multipleCancelActionFeedback() throws Exception { - final Target target = new Target("4712"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement, true); - final DistributionSet ds2 = TestDataUtil.generateDistributionSet("2", softwareManagement, - distributionSetManagement, true); - final DistributionSet ds3 = TestDataUtil.generateDistributionSet("3", softwareManagement, - distributionSetManagement, true); + final Target target = entityFactory.generateTarget("4712"); + final DistributionSet ds = testdataFactory.createDistributionSet("", true); + final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true); + final DistributionSet ds3 = testdataFactory.createDistributionSet("3", true); final Target savedTarget = targetManagement.createTarget(target); @@ -350,7 +343,7 @@ public class CancelActionTest extends AbstractIntegrationTest { final Action updateAction3 = deploymentManagement.findActionWithDetails( deploymentManagement.assignDistributionSet(ds3.getId(), new String[] { "4712" }).getActions().get(0)); - assertThat(actionStatusRepository.findAll()).hasSize(3); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(3); // 3 update actions, 0 cancel actions assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(3); @@ -369,7 +362,7 @@ public class CancelActionTest extends AbstractIntegrationTest { .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$id", equalTo(String.valueOf(cancelAction.getId())))) .andExpect(jsonPath("$cancelAction.stopId", equalTo(String.valueOf(updateAction.getId())))); - assertThat(actionStatusRepository.findAll()).hasSize(6); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(6); mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant())) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) @@ -385,7 +378,7 @@ public class CancelActionTest extends AbstractIntegrationTest { .content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed")) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); - assertThat(actionStatusRepository.findAll()).hasSize(7); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(7); // 1 update actions, 1 cancel actions assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(2); @@ -395,7 +388,7 @@ public class CancelActionTest extends AbstractIntegrationTest { .andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$id", equalTo(String.valueOf(cancelAction2.getId())))) .andExpect(jsonPath("$cancelAction.stopId", equalTo(String.valueOf(updateAction2.getId())))); - assertThat(actionStatusRepository.findAll()).hasSize(8); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(8); mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant())) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) @@ -411,17 +404,18 @@ public class CancelActionTest extends AbstractIntegrationTest { .content(JsonBuilder.cancelActionFeedback(cancelAction2.getId().toString(), "closed")) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); - assertThat(actionStatusRepository.findAll()).hasSize(9); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(9); assertThat(targetManagement.findTargetByControllerID("4712").getAssignedDistributionSet()).isEqualTo(ds3); mvc.perform(get("/{tenant}/controller/v1/4712/deploymentBase/" + updateAction3.getId(), tenantAware.getCurrentTenant())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); - assertThat(actionStatusRepository.findAll()).hasSize(10); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(10); // 1 update actions, 0 cancel actions assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(1); - final Action cancelAction3 = deploymentManagement.cancelAction(actionRepository.findOne(updateAction3.getId()), + final Action cancelAction3 = deploymentManagement.cancelAction( + deploymentManagement.findAction(updateAction3.getId()), targetManagement.findTargetByControllerID(savedTarget.getControllerId())); // action is in cancelling state @@ -434,7 +428,7 @@ public class CancelActionTest extends AbstractIntegrationTest { .andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$id", equalTo(String.valueOf(cancelAction3.getId())))) .andExpect(jsonPath("$cancelAction.stopId", equalTo(String.valueOf(updateAction3.getId())))); - assertThat(actionStatusRepository.findAll()).hasSize(12); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(12); // now lets return feedback for the third cancelation mvc.perform(post("/{tenant}/controller/v1/4712/cancelAction/" + cancelAction3.getId() + "/feedback", @@ -442,7 +436,7 @@ public class CancelActionTest extends AbstractIntegrationTest { .content(JsonBuilder.cancelActionFeedback(cancelAction3.getId().toString(), "closed")) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); - assertThat(actionStatusRepository.findAll()).hasSize(13); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(13); // final status assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(0); @@ -452,9 +446,8 @@ public class CancelActionTest extends AbstractIntegrationTest { @Test @Description("Tests the feeback channel closing for too many feedbacks, i.e. denial of service prevention.") public void tooMuchCancelActionFeedback() throws Exception { - final Target target = targetManagement.createTarget(new Target("4712")); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final Target target = targetManagement.createTarget(entityFactory.generateTarget("4712")); + final DistributionSet ds = testdataFactory.createDistributionSet(""); final List toAssign = new ArrayList(); toAssign.add(target); diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/ConfigDataTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiConfigDataTest.java similarity index 93% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/ConfigDataTest.java rename to hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiConfigDataTest.java index a2b26c218..395e2284c 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/ConfigDataTest.java +++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiConfigDataTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller; +package org.eclipse.hawkbit.ddi.rest.resource; import static org.fest.assertions.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.equalTo; @@ -21,10 +21,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.util.HashMap; import java.util.Map; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.MockMvcResultPrinter; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.rest.resource.JsonBuilder; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; +import org.eclipse.hawkbit.rest.util.JsonBuilder; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.junit.Test; import org.springframework.hateoas.MediaTypes; import org.springframework.http.MediaType; @@ -34,16 +34,19 @@ import ru.yandex.qatools.allure.annotations.Description; import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; +/** + * Test config data from the controller. + */ @ActiveProfiles({ "im", "test" }) @Features("Component Tests - Direct Device Integration API") @Stories("Config Data Resource") -public class ConfigDataTest extends AbstractIntegrationTest { +public class DdiConfigDataTest extends AbstractRestIntegrationTest { @Test @Description("We verify that the config data (i.e. device attributes like serial number, hardware revision etc.) " + "are requested only once from the device.") public void requestConfigDataIfEmpty() throws Exception { - final Target target = new Target("4712"); + final Target target = entityFactory.generateTarget("4712"); final Target savedTarget = targetManagement.createTarget(target); final long current = System.currentTimeMillis(); @@ -81,7 +84,7 @@ public class ConfigDataTest extends AbstractIntegrationTest { @Description("We verify that the config data (i.e. device attributes like serial number, hardware revision etc.) " + "can be uploaded correctly by the controller.") public void putConfigData() throws Exception { - targetManagement.createTarget(new Target("4717")); + targetManagement.createTarget(entityFactory.generateTarget("4717")); // initial final Map attributes = new HashMap<>(); @@ -124,7 +127,7 @@ public class ConfigDataTest extends AbstractIntegrationTest { @Description("We verify that the config data (i.e. device attributes like serial number, hardware revision etc.) " + "upload limitation is inplace which is meant to protect the server from malicious attempts.") public void putToMuchConfigData() throws Exception { - targetManagement.createTarget(new Target("4717")); + targetManagement.createTarget(entityFactory.generateTarget("4717")); // initial Map attributes = new HashMap<>(); @@ -147,7 +150,7 @@ public class ConfigDataTest extends AbstractIntegrationTest { @Description("We verify that the config data (i.e. device attributes like serial number, hardware revision etc.) " + "resource behaves as exptected in cae of invalid request attempts.") public void badConfigData() throws Exception { - final Target target = new Target("4712"); + final Target target = entityFactory.generateTarget("4712"); final Target savedTarget = targetManagement.createTarget(target); // not allowed methods diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/DeploymentBaseTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java similarity index 79% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/DeploymentBaseTest.java rename to hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java index 5dd956ad3..0ec0d0d7e 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/DeploymentBaseTest.java +++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller; +package org.eclipse.hawkbit.ddi.rest.resource; import static org.fest.assertions.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.equalTo; @@ -23,43 +23,50 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.RandomUtils; -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.TestDataUtil; +import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.RepositoryModelConstants; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.rest.resource.JsonBuilder; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB; +import org.eclipse.hawkbit.rest.util.JsonBuilder; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.fest.assertions.core.Condition; import org.junit.Test; import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.hateoas.MediaTypes; import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MvcResult; + +import com.jayway.jsonpath.JsonPath; import ru.yandex.qatools.allure.annotations.Description; import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; -@ActiveProfiles({ "im", "test" }) +/** + * Test deployment base from the controller. + */ @Features("Component Tests - Direct Device Integration API") @Stories("Deployment Action Resource") -public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { +public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoDB { + + private static final String HTTP_LOCALHOST = "http://localhost:8080/"; + private static final String HTTPS_LOCALHOST = "https://localhost:8080/"; @Test() @Description("Ensures that artifacts are not found, when softare module does not exists.") public void artifactsNotFound() throws Exception { - final Target target = TestDataUtil.createTarget(targetManagement); + final Target target = testdataFactory.createTarget(); final Long softwareModuleIdNotExist = 1l; mvc.perform(get("/{tenant}/controller/v1/{targetNotExist}/softwaremodules/{softwareModuleId}/artifacts", tenantAware.getCurrentTenant(), target.getName(), softwareModuleIdNotExist)) @@ -69,9 +76,8 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { @Test() @Description("Ensures that artifacts are found, when software module exists.") public void artifactsExists() throws Exception { - final Target target = TestDataUtil.createTarget(targetManagement); - final DistributionSet distributionSet = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final Target target = testdataFactory.createTarget(); + final DistributionSet distributionSet = testdataFactory.createDistributionSet(""); deploymentManagement.assignDistributionSet(distributionSet.getId(), new String[] { target.getName() }); @@ -80,7 +86,7 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { tenantAware.getCurrentTenant(), target.getName(), softwareModuleId)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()).andExpect(jsonPath("$", hasSize(0))); - TestDataUtil.generateArtifacts(artifactManagement, softwareModuleId); + testdataFactory.createLocalArtifacts(softwareModuleId); mvc.perform(get("/{tenant}/controller/v1/{targetNotExist}/softwaremodules/{softwareModuleId}/artifacts", tenantAware.getCurrentTenant(), target.getName(), softwareModuleId)).andDo(MockMvcResultPrinter.print()) @@ -95,11 +101,9 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { @Description("Forced deployment to a controller. Checks if the resource reponse payload for a given deployment is as expected.") public void deplomentForceAction() throws Exception { // Prepare test data - final Target target = new Target("4712"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement, true); - final DistributionSet ds2 = TestDataUtil.generateDistributionSet("2", softwareManagement, - distributionSetManagement, true); + final Target target = entityFactory.generateTarget("4712"); + final DistributionSet ds = testdataFactory.createDistributionSet("", true); + final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true); final byte random[] = RandomUtils.nextBytes(5 * 1024); final LocalArtifact artifact = artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), @@ -110,18 +114,18 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { final Target savedTarget = targetManagement.createTarget(target); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).isEmpty(); - assertThat(actionRepository.findAll()).isEmpty(); - assertThat(actionStatusRepository.findAll()).isEmpty(); + assertThat(deploymentManagement.countActionsAll()).isEqualTo(0); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(0); List saved = deploymentManagement.assignDistributionSet(ds.getId(), ActionType.FORCED, - Action.NO_FORCE_TIME, savedTarget.getControllerId()).getAssignedEntity(); + RepositoryModelConstants.NO_FORCE_TIME, savedTarget.getControllerId()).getAssignedEntity(); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(1); final Action action = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); - assertThat(actionRepository.findAll()).hasSize(1); + assertThat(deploymentManagement.countActionsAll()).isEqualTo(1); saved = deploymentManagement.assignDistributionSet(ds2, saved).getAssignedEntity(); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(2); - assertThat(actionRepository.findAll()).hasSize(2); + assertThat(deploymentManagement.countActionsAll()).isEqualTo(2); final Action uaction = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); assertThat(uaction.getDistributionSet()).isEqualTo(ds); @@ -139,7 +143,7 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { .isGreaterThanOrEqualTo(current); assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getLastTargetQuery()) .isLessThanOrEqualTo(System.currentTimeMillis()); - assertThat(actionStatusRepository.findAll()).hasSize(2); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(2); current = System.currentTimeMillis(); @@ -170,24 +174,22 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1", equalTo(artifact.getSha1Hash()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.MD5SUM"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download-http.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() - + "/controller/v1/4712/softwaremodules/" + equalTo(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum-http.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() - + "/controller/v1/4712/softwaremodules/" + equalTo(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.MD5SUM"))) @@ -200,23 +202,21 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1", equalTo(artifactSignature.getSha1Hash()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature.MD5SUM"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download-http.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() - + "/controller/v1/4712/softwaremodules/" + equalTo(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum-http.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() - + "/controller/v1/4712/softwaremodules/" + equalTo(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature.MD5SUM"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==bApp)][0].version", @@ -227,22 +227,59 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { .isGreaterThanOrEqualTo(current); // Retrieved is reported - final Iterable actionStatusMessages = actionStatusRepository - .findAll(new PageRequest(0, 100, Direction.DESC, "id")); - assertThat(actionStatusMessages).hasSize(3); + final Iterable actionStatusMessages = deploymentManagement + .findActionStatusByAction(new PageRequest(0, 100, Direction.DESC, "id"), uaction); + assertThat(actionStatusMessages).hasSize(2); final ActionStatus actionStatusMessage = actionStatusMessages.iterator().next(); assertThat(actionStatusMessage.getStatus()).isEqualTo(Status.RETRIEVED); } + @Test + @Description("Checks that the deployementBase URL changes when the action is switched from soft to forced in TIMEFORCED case.") + public void changeEtagIfActionSwitchesFromSoftToForced() throws Exception { + // Prepare test data + final Target target = targetManagement.createTarget(entityFactory.generateTarget("4712")); + final DistributionSet ds = testdataFactory.createDistributionSet("", true); + + final DistributionSetAssignmentResult result = deploymentManagement.assignDistributionSet(ds.getId(), + ActionType.TIMEFORCED, System.currentTimeMillis() + 1_000, target.getControllerId()); + + final Action action = deploymentManagement.findActiveActionsByTarget(result.getAssignedEntity().get(0)).get(0); + + MvcResult mvcResult = mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant())) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(content().contentType(MediaTypes.HAL_JSON)).andReturn(); + + final String urlBeforeSwitch = JsonPath.compile("_links.deploymentBase.href") + .read(mvcResult.getResponse().getContentAsString()).toString(); + + // Time is not yet over, so we should see the same URL + mvcResult = mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant())) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(content().contentType(MediaTypes.HAL_JSON)).andReturn(); + assertThat(JsonPath.compile("_links.deploymentBase.href").read(mvcResult.getResponse().getContentAsString()) + .toString()).isEqualTo(urlBeforeSwitch) + .startsWith("http://localhost/" + tenantAware.getCurrentTenant() + + "/controller/v1/4712/deploymentBase/" + action.getId()); + + // After the time is over we should see a new etag + TimeUnit.MILLISECONDS.sleep(1_000); + + mvcResult = mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant())) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(content().contentType(MediaTypes.HAL_JSON)).andReturn(); + + assertThat(JsonPath.compile("_links.deploymentBase.href").read(mvcResult.getResponse().getContentAsString()) + .toString()).isNotEqualTo(urlBeforeSwitch); + } + @Test @Description("Attempt/soft deployment to a controller. Checks if the resource reponse payload for a given deployment is as expected.") public void deplomentAttemptAction() throws Exception { // Prepare test data - final Target target = new Target("4712"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement, true); - final DistributionSet ds2 = TestDataUtil.generateDistributionSet("2", softwareManagement, - distributionSetManagement, true); + final Target target = entityFactory.generateTarget("4712"); + final DistributionSet ds = testdataFactory.createDistributionSet("", true); + final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true); final byte random[] = RandomUtils.nextBytes(5 * 1024); final LocalArtifact artifact = artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), @@ -253,19 +290,18 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { final Target savedTarget = targetManagement.createTarget(target); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).isEmpty(); - assertThat(actionRepository.findAll()).isEmpty(); - assertThat(actionStatusRepository.findAll()).isEmpty(); + assertThat(deploymentManagement.countActionsAll()).isEqualTo(0); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(0); - List saved = deploymentManagement - .assignDistributionSet(ds.getId(), ActionType.SOFT, Action.NO_FORCE_TIME, savedTarget.getControllerId()) - .getAssignedEntity(); + List saved = deploymentManagement.assignDistributionSet(ds.getId(), ActionType.SOFT, + RepositoryModelConstants.NO_FORCE_TIME, savedTarget.getControllerId()).getAssignedEntity(); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(1); final Action action = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); - assertThat(actionRepository.findAll()).hasSize(1); + assertThat(deploymentManagement.countActionsAll()).isEqualTo(1); saved = deploymentManagement.assignDistributionSet(ds2, saved).getAssignedEntity(); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(2); - assertThat(actionRepository.findAll()).hasSize(2); + assertThat(deploymentManagement.countActionsAll()).isEqualTo(2); final Action uaction = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); assertThat(uaction.getDistributionSet()).isEqualTo(ds); @@ -284,7 +320,7 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { .isGreaterThanOrEqualTo(current); assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getLastTargetQuery()) .isLessThanOrEqualTo(System.currentTimeMillis()); - assertThat(actionStatusRepository.findAll()).hasSize(2); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(2); current = System.currentTimeMillis(); @@ -315,12 +351,12 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1", equalTo(artifact.getSha1Hash()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.MD5SUM"))) @@ -333,23 +369,21 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1", equalTo(artifactSignature.getSha1Hash()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature.MD5SUM"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download-http.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() - + "/controller/v1/4712/softwaremodules/" + equalTo(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum-http.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() - + "/controller/v1/4712/softwaremodules/" + equalTo(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature.MD5SUM"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==bApp)][0].version", @@ -360,9 +394,9 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { .isGreaterThanOrEqualTo(current); // Retrieved is reported - final Iterable actionStatusMessages = actionStatusRepository - .findAll(new PageRequest(0, 100, Direction.DESC, "id")); - assertThat(actionStatusMessages).hasSize(3); + final List actionStatusMessages = deploymentManagement + .findActionStatusByAction(new PageRequest(0, 100, Direction.DESC, "id"), uaction).getContent(); + assertThat(actionStatusMessages).hasSize(2); final ActionStatus actionStatusMessage = actionStatusMessages.iterator().next(); assertThat(actionStatusMessage.getStatus()).isEqualTo(Status.RETRIEVED); } @@ -371,11 +405,9 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { @Description("Attempt/soft deployment to a controller including automated switch to hard. Checks if the resource reponse payload for a given deployment is as expected.") public void deplomentAutoForceAction() throws Exception { // Prepare test data - final Target target = new Target("4712"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement, true); - final DistributionSet ds2 = TestDataUtil.generateDistributionSet("2", softwareManagement, - distributionSetManagement, true); + final Target target = entityFactory.generateTarget("4712"); + final DistributionSet ds = testdataFactory.createDistributionSet("", true); + final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true); final byte random[] = RandomUtils.nextBytes(5 * 1024); final LocalArtifact artifact = artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), @@ -386,18 +418,18 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { final Target savedTarget = targetManagement.createTarget(target); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).isEmpty(); - assertThat(actionRepository.findAll()).isEmpty(); - assertThat(actionStatusRepository.findAll()).isEmpty(); + assertThat(deploymentManagement.countActionsAll()).isEqualTo(0); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(0); List saved = deploymentManagement.assignDistributionSet(ds.getId(), ActionType.TIMEFORCED, System.currentTimeMillis(), savedTarget.getControllerId()).getAssignedEntity(); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(1); final Action action = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); - assertThat(actionRepository.findAll()).hasSize(1); + assertThat(deploymentManagement.countActionsAll()).isEqualTo(1); saved = deploymentManagement.assignDistributionSet(ds2, saved).getAssignedEntity(); assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget)).hasSize(2); - assertThat(actionRepository.findAll()).hasSize(2); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(2); final Action uaction = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); assertThat(uaction.getDistributionSet()).isEqualTo(ds); @@ -416,7 +448,7 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { .isGreaterThanOrEqualTo(current); assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getLastTargetQuery()) .isLessThanOrEqualTo(System.currentTimeMillis()); - assertThat(actionStatusRepository.findAll()).hasSize(2); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(2); current = System.currentTimeMillis(); @@ -445,23 +477,21 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { equalTo(artifact.getSha1Hash()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.MD5SUM"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download-http.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() - + "/controller/v1/4712/softwaremodules/" + equalTo(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum-http.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() - + "/controller/v1/4712/softwaremodules/" + equalTo(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.MD5SUM"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].size", equalTo(5 * 1024))) @@ -473,24 +503,22 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1", equalTo(artifactSignature.getSha1Hash()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href", - equalTo("https://localhost/" + tenantAware.getCurrentTenant() + equalTo(HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature.MD5SUM"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download-http.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() - + "/controller/v1/4712/softwaremodules/" + equalTo(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum-http.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() - + "/controller/v1/4712/softwaremodules/" + equalTo(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature.MD5SUM"))) @@ -502,9 +530,9 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { .isGreaterThanOrEqualTo(current); // Retrieved is reported - final Iterable actionStatusMessages = actionStatusRepository - .findAll(new PageRequest(0, 100, Direction.DESC, "id")); - assertThat(actionStatusMessages).hasSize(3); + final Iterable actionStatusMessages = deploymentManagement + .findActionStatusByAction(new PageRequest(0, 100, Direction.DESC, "id"), uaction).getContent(); + assertThat(actionStatusMessages).hasSize(2); final ActionStatus actionStatusMessage = actionStatusMessages.iterator().next(); assertThat(actionStatusMessage.getStatus()).isEqualTo(Status.RETRIEVED); } @@ -512,7 +540,7 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Test various invalid access attempts to the deployment resource und the expected behaviour of the server.") public void badDeploymentAction() throws Exception { - final Target target = targetManagement.createTarget(new Target("4712")); + final Target target = targetManagement.createTarget(entityFactory.generateTarget("4712")); // not allowed methods mvc.perform(post("/{tenant}/controller/v1/4712/deploymentBase/1", tenantAware.getCurrentTenant())) @@ -533,10 +561,9 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { .andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound()); // wrong media type - final List toAssign = new ArrayList(); + final List toAssign = new ArrayList<>(); toAssign.add(target); - final DistributionSet savedSet = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet savedSet = testdataFactory.createDistributionSet(""); final Action action1 = deploymentManagement.findActionWithDetails( deploymentManagement.assignDistributionSet(savedSet, toAssign).getActions().get(0)); @@ -553,16 +580,14 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { @Description("The server protects itself against to many feedback upload attempts. The test verfies that " + "it is not possible to exceed the configured maximum number of feedback uplods.") public void toMuchDeplomentActionFeedback() throws Exception { - final Target target = targetManagement.createTarget(new Target("4712")); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final Target target = targetManagement.createTarget(entityFactory.generateTarget("4712")); + final DistributionSet ds = testdataFactory.createDistributionSet(""); - final List toAssign = new ArrayList(); + final List toAssign = new ArrayList<>(); toAssign.add(target); deploymentManagement.assignDistributionSet(ds.getId(), new String[] { "4712" }); - final Pageable pageReq = new PageRequest(0, 100); - final Action action = actionRepository.findByDistributionSet(pageReq, ds).getContent().get(0); + final Action action = deploymentManagement.findActionsByTarget(target).get(0); final String feedback = JsonBuilder.deploymentActionFeedback(action.getId().toString(), "proceeding"); // assign distribution set creates an action status, so only 99 left @@ -582,21 +607,18 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Multiple uploads of deployment status feedback to the server.") public void multipleDeplomentActionFeedback() throws Exception { - final Target target1 = new Target("4712"); - final Target target2 = new Target("4713"); - final Target target3 = new Target("4714"); + final Target target1 = entityFactory.generateTarget("4712"); + final Target target2 = entityFactory.generateTarget("4713"); + final Target target3 = entityFactory.generateTarget("4714"); final Target savedTarget1 = targetManagement.createTarget(target1); targetManagement.createTarget(target2); targetManagement.createTarget(target3); - final DistributionSet ds1 = TestDataUtil.generateDistributionSet("1", softwareManagement, - distributionSetManagement, true); - final DistributionSet ds2 = TestDataUtil.generateDistributionSet("2", softwareManagement, - distributionSetManagement, true); - final DistributionSet ds3 = TestDataUtil.generateDistributionSet("3", softwareManagement, - distributionSetManagement, true); + final DistributionSet ds1 = testdataFactory.createDistributionSet("1", true); + final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true); + final DistributionSet ds3 = testdataFactory.createDistributionSet("3", true); - final List toAssign = new ArrayList(); + final List toAssign = new ArrayList<>(); toAssign.add(savedTarget1); final Action action1 = deploymentManagement.findActionWithDetails( @@ -636,7 +658,8 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { assertThat(myT.getTargetInfo().getInstalledDistributionSet().getId()).isEqualTo(ds1.getId()); assertThat(myT.getAssignedDistributionSet()).isEqualTo(ds3); - Iterable actionStatusMessages = actionStatusRepository.findAll(new Sort(Direction.DESC, "id")); + Iterable actionStatusMessages = deploymentManagement + .findActionStatusAll(new PageRequest(0, 100, Direction.DESC, "id")).getContent(); assertThat(actionStatusMessages).hasSize(4); assertThat(actionStatusMessages.iterator().next().getStatus()).isEqualTo(Status.FINISHED); @@ -656,7 +679,8 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { assertThat(deploymentManagement.findActiveActionsByTarget(myT)).hasSize(1); assertThat(myT.getTargetInfo().getInstalledDistributionSet().getId()).isEqualTo(ds2.getId()); assertThat(myT.getAssignedDistributionSet()).isEqualTo(ds3); - actionStatusMessages = actionStatusRepository.findAll(new PageRequest(0, 100, Direction.DESC, "id")); + actionStatusMessages = deploymentManagement.findActionStatusAll(new PageRequest(0, 100, Direction.DESC, "id")) + .getContent(); assertThat(actionStatusMessages).hasSize(5); assertThat(actionStatusMessages).haveAtLeast(1, new ActionStatusCondition(Status.FINISHED)); @@ -675,7 +699,8 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { assertThat(deploymentManagement.findActiveActionsByTarget(myT)).hasSize(0); assertThat(myT.getTargetInfo().getInstalledDistributionSet()).isEqualTo(ds3); assertThat(myT.getAssignedDistributionSet()).isEqualTo(ds3); - actionStatusMessages = actionStatusRepository.findAll(); + actionStatusMessages = deploymentManagement.findActionStatusAll(new PageRequest(0, 100, Direction.DESC, "id")) + .getContent(); assertThat(actionStatusMessages).hasSize(6); assertThat(actionStatusMessages).haveAtLeast(1, new ActionStatusCondition(Status.FINISHED)); @@ -684,18 +709,18 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Verfies that an update action is correctly set to error if the controller provides error feedback.") public void rootRsSingleDeplomentActionWithErrorFeedback() throws Exception { - final Target target = new Target("4712"); - DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, distributionSetManagement); + final Target target = entityFactory.generateTarget("4712"); + DistributionSet ds = testdataFactory.createDistributionSet(""); final Target savedTarget = targetManagement.createTarget(target); - List toAssign = new ArrayList(); + List toAssign = new ArrayList<>(); toAssign.add(savedTarget); assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getUpdateStatus()) .isEqualTo(TargetUpdateStatus.UNKNOWN); deploymentManagement.assignDistributionSet(ds, toAssign); - final Action action = actionRepository.findByDistributionSet(pageReq, ds).getContent().get(0); + final Action action = deploymentManagement.findActionsByDistributionSet(pageReq, ds).getContent().get(0); long current = System.currentTimeMillis(); long lastModified = targetManagement.findTargetByControllerID("4712").getLastModifiedAt(); @@ -718,7 +743,8 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { .hasSize(0); assertThat(deploymentManagement.findActiveActionsByTarget(myT)).hasSize(0); assertThat(deploymentManagement.findActionsByTarget(myT)).hasSize(1); - final Iterable actionStatusMessages = actionStatusRepository.findAll(); + final Iterable actionStatusMessages = deploymentManagement + .findActionStatusAll(new PageRequest(0, 100, Direction.DESC, "id")).getContent(); assertThat(actionStatusMessages).hasSize(2); assertThat(actionStatusMessages).haveAtLeast(1, new ActionStatusCondition(Status.ERROR)); @@ -749,10 +775,10 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { .hasSize(1); assertThat(deploymentManagement.findActiveActionsByTarget(myT)).hasSize(0); assertThat(deploymentManagement.findInActiveActionsByTarget(myT)).hasSize(2); - assertThat(actionStatusRepository.findAll()).hasSize(4); - assertThat(actionStatusRepository.findByAction(pageReq, action).getContent()).haveAtLeast(1, + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(4); + assertThat(deploymentManagement.findActionStatusByAction(pageReq, action).getContent()).haveAtLeast(1, new ActionStatusCondition(Status.ERROR)); - assertThat(actionStatusRepository.findByAction(pageReq, action2).getContent()).haveAtLeast(1, + assertThat(deploymentManagement.findActionStatusByAction(pageReq, action2).getContent()).haveAtLeast(1, new ActionStatusCondition(Status.FINISHED)); } @@ -760,27 +786,23 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Verfies that the controller can provided as much feedback entries as necessry as long as it is in the configured limites.") public void rootRsSingleDeplomentActionFeedback() throws Exception { - final Target target = new Target("4712"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final Target target = entityFactory.generateTarget("4712"); + final DistributionSet ds = testdataFactory.createDistributionSet(""); final Target savedTarget = targetManagement.createTarget(target); - final List toAssign = new ArrayList(); + final List toAssign = new ArrayList<>(); toAssign.add(savedTarget); Target myT = targetManagement.findTargetByControllerID("4712"); assertThat(myT.getTargetInfo().getUpdateStatus()).isEqualTo(TargetUpdateStatus.UNKNOWN); deploymentManagement.assignDistributionSet(ds, toAssign); - final Action action = actionRepository.findByDistributionSet(pageReq, ds).getContent().get(0); + final Action action = deploymentManagement.findActionsByDistributionSet(pageReq, ds).getContent().get(0); myT = targetManagement.findTargetByControllerID("4712"); assertThat(myT.getTargetInfo().getUpdateStatus()).isEqualTo(TargetUpdateStatus.PENDING); - assertThat(targetRepository.findByTargetInfoInstalledDistributionSet(new PageRequest(0, 10), ds)).hasSize(0); - assertThat(targetRepository.findByAssignedDistributionSet(new PageRequest(0, 10), ds)).hasSize(1); - assertThat(targetRepository - .findByAssignedDistributionSetOrTargetInfoInstalledDistributionSet(new PageRequest(0, 10), ds, ds)) - .hasSize(1); + assertThat(targetManagement.findTargetByInstalledDistributionSet(ds.getId(), pageReq)).hasSize(0); + assertThat(targetManagement.findTargetByAssignedDistributionSet(ds.getId(), pageReq)).hasSize(1); // Now valid Feedback @@ -804,8 +826,9 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { assertThat(targetManagement.findTargetByUpdateStatus(new PageRequest(0, 10), TargetUpdateStatus.IN_SYNC)) .hasSize(0); assertThat(deploymentManagement.findActiveActionsByTarget(myT)).hasSize(1); - assertThat(actionStatusRepository.findAll()).hasSize(5); - assertThat(actionStatusRepository.findAll()).haveAtLeast(5, new ActionStatusCondition(Status.RUNNING)); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(5); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(5, + new ActionStatusCondition(Status.RUNNING)); current = System.currentTimeMillis(); mvc.perform(post("/{tenant}/controller/v1/4712/deploymentBase/" + action.getId() + "/feedback", @@ -823,8 +846,9 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { assertThat(targetManagement.findTargetByUpdateStatus(new PageRequest(0, 10), TargetUpdateStatus.IN_SYNC)) .hasSize(0); assertThat(deploymentManagement.findActiveActionsByTarget(myT)).hasSize(1); - assertThat(actionStatusRepository.findAll()).hasSize(6); - assertThat(actionStatusRepository.findAll()).haveAtLeast(5, new ActionStatusCondition(Status.RUNNING)); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(6); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(5, + new ActionStatusCondition(Status.RUNNING)); current = System.currentTimeMillis(); mvc.perform(post("/{tenant}/controller/v1/4712/deploymentBase/" + action.getId() + "/feedback", @@ -842,8 +866,9 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { assertThat(targetManagement.findTargetByUpdateStatus(new PageRequest(0, 10), TargetUpdateStatus.IN_SYNC)) .hasSize(0); assertThat(deploymentManagement.findActiveActionsByTarget(myT)).hasSize(1); - assertThat(actionStatusRepository.findAll()).hasSize(7); - assertThat(actionStatusRepository.findAll()).haveAtLeast(6, new ActionStatusCondition(Status.RUNNING)); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(7); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(6, + new ActionStatusCondition(Status.RUNNING)); current = System.currentTimeMillis(); mvc.perform(post("/{tenant}/controller/v1/4712/deploymentBase/" + action.getId() + "/feedback", @@ -862,9 +887,11 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { assertThat(targetManagement.findTargetByUpdateStatus(new PageRequest(0, 10), TargetUpdateStatus.IN_SYNC)) .hasSize(0); - assertThat(actionStatusRepository.findAll()).hasSize(8); - assertThat(actionStatusRepository.findAll()).haveAtLeast(7, new ActionStatusCondition(Status.RUNNING)); - assertThat(actionStatusRepository.findAll()).haveAtLeast(1, new ActionStatusCondition(Status.CANCELED)); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(8); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(7, + new ActionStatusCondition(Status.RUNNING)); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(1, + new ActionStatusCondition(Status.CANCELED)); current = System.currentTimeMillis(); mvc.perform(post("/{tenant}/controller/v1/4712/deploymentBase/" + action.getId() + "/feedback", @@ -876,10 +903,13 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { assertThat(myT.getTargetInfo().getLastTargetQuery()).isGreaterThanOrEqualTo(current); assertThat(myT.getTargetInfo().getUpdateStatus()).isEqualTo(TargetUpdateStatus.PENDING); assertThat(deploymentManagement.findActiveActionsByTarget(myT)).hasSize(1); - assertThat(actionStatusRepository.findAll()).hasSize(9); - assertThat(actionStatusRepository.findAll()).haveAtLeast(6, new ActionStatusCondition(Status.RUNNING)); - assertThat(actionStatusRepository.findAll()).haveAtLeast(1, new ActionStatusCondition(Status.WARNING)); - assertThat(actionStatusRepository.findAll()).haveAtLeast(1, new ActionStatusCondition(Status.CANCELED)); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(9); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(6, + new ActionStatusCondition(Status.RUNNING)); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(1, + new ActionStatusCondition(Status.WARNING)); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(1, + new ActionStatusCondition(Status.CANCELED)); current = System.currentTimeMillis(); mvc.perform(post("/{tenant}/controller/v1/4712/deploymentBase/" + action.getId() + "/feedback", @@ -896,28 +926,27 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { assertThat(targetManagement.findTargetByUpdateStatus(new PageRequest(0, 10), TargetUpdateStatus.IN_SYNC)) .hasSize(1); - assertThat(actionStatusRepository.findAll()).hasSize(10); - assertThat(actionStatusRepository.findAll()).haveAtLeast(7, new ActionStatusCondition(Status.RUNNING)); - assertThat(actionStatusRepository.findAll()).haveAtLeast(1, new ActionStatusCondition(Status.WARNING)); - assertThat(actionStatusRepository.findAll()).haveAtLeast(1, new ActionStatusCondition(Status.CANCELED)); - assertThat(actionStatusRepository.findAll()).haveAtLeast(1, new ActionStatusCondition(Status.FINISHED)); + assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(10); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(7, + new ActionStatusCondition(Status.RUNNING)); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(1, + new ActionStatusCondition(Status.WARNING)); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(1, + new ActionStatusCondition(Status.CANCELED)); + assertThat(deploymentManagement.findActionStatusAll(pageReq).getContent()).haveAtLeast(1, + new ActionStatusCondition(Status.FINISHED)); - assertThat(targetRepository.findByTargetInfoInstalledDistributionSet(new PageRequest(0, 10), ds)).hasSize(1); - assertThat(targetRepository.findByAssignedDistributionSet(new PageRequest(0, 10), ds)).hasSize(1); - assertThat(targetRepository - .findByAssignedDistributionSetOrTargetInfoInstalledDistributionSet(new PageRequest(0, 10), ds, ds)) - .hasSize(1); + assertThat(targetManagement.findTargetByInstalledDistributionSet(ds.getId(), pageReq)).hasSize(1); + assertThat(targetManagement.findTargetByAssignedDistributionSet(ds.getId(), pageReq)).hasSize(1); } @Test @Description("Various forbidden request appempts on the feedback resource. Ensures correct answering behaviour as expected to these kind of errors.") public void badDeplomentActionFeedback() throws Exception { - final Target target = new Target("4712"); - final Target target2 = new Target("4713"); - final DistributionSet savedSet = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); - final DistributionSet savedSet2 = TestDataUtil.generateDistributionSet("1", softwareManagement, - distributionSetManagement); + final Target target = entityFactory.generateTarget("4712"); + final Target target2 = entityFactory.generateTarget("4713"); + final DistributionSet savedSet = testdataFactory.createDistributionSet(""); + final DistributionSet savedSet2 = testdataFactory.createDistributionSet("1"); // target does not exist mvc.perform(post("/{tenant}/controller/v1/4712/deploymentBase/1234/feedback", tenantAware.getCurrentTenant()) diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/RootControllerTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java similarity index 86% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/RootControllerTest.java rename to hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java index fa2c5f6d4..31ec37c58 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/RootControllerTest.java +++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller; +package org.eclipse.hawkbit.ddi.rest.resource; import static org.fest.assertions.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.equalTo; @@ -22,33 +22,38 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.util.ArrayList; import java.util.List; -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.WithSpringAuthorityRule; -import org.eclipse.hawkbit.WithUser; import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.rest.resource.JsonBuilder; +import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule; +import org.eclipse.hawkbit.repository.test.util.WithUser; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB; +import org.eclipse.hawkbit.rest.util.JsonBuilder; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; +import org.eclipse.hawkbit.security.HawkbitSecurityProperties; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.eclipse.hawkbit.util.IpUtil; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.MediaTypes; import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; import ru.yandex.qatools.allure.annotations.Description; import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; -@ActiveProfiles({ "im", "test" }) +/** + * Test the root controller resources. + */ @Features("Component Tests - Direct Device Integration API") @Stories("Root Poll Resource") -public class RootControllerTest extends AbstractIntegrationTestWithMongoDB { +public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoDB { + + @Autowired + private HawkbitSecurityProperties securityProperties; @Test @Description("Ensures that targets cannot be created e.g. in plug'n play scenarios when tenant does not exists but can be created if the tenant exists.") @@ -79,7 +84,7 @@ public class RootControllerTest extends AbstractIntegrationTestWithMongoDB { // create target first with "knownPrincipal" user and audit data final String knownTargetControllerId = "target1"; final String knownCreatedBy = "knownPrincipal"; - targetManagement.createTarget(new Target(knownTargetControllerId)); + targetManagement.createTarget(entityFactory.generateTarget(knownTargetControllerId)); final Target findTargetByControllerID = targetManagement.findTargetByControllerID(knownTargetControllerId); assertThat(findTargetByControllerID.getCreatedBy()).isEqualTo(knownCreatedBy); assertThat(findTargetByControllerID.getCreatedAt()).isNotNull(); @@ -120,7 +125,7 @@ public class RootControllerTest extends AbstractIntegrationTestWithMongoDB { assertThat(targetManagement.findTargetByControllerID("4711").getTargetInfo().getLastTargetQuery()) .isGreaterThanOrEqualTo(current); - assertThat(targetRepository.findByControllerId("4711").getTargetInfo().getUpdateStatus()) + assertThat(targetManagement.findTargetByControllerID("4711").getTargetInfo().getUpdateStatus()) .isEqualTo(TargetUpdateStatus.REGISTERED); // not allowed methods @@ -168,9 +173,8 @@ public class RootControllerTest extends AbstractIntegrationTestWithMongoDB { mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()).header("If-None-Match", etag)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isNotModified()); - final Target target = targetRepository.findByControllerId("4711"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final Target target = targetManagement.findTargetByControllerID("4711"); + final DistributionSet ds = testdataFactory.createDistributionSet(""); deploymentManagement.assignDistributionSet(ds.getId(), new String[] { "4711" }); @@ -203,8 +207,7 @@ public class RootControllerTest extends AbstractIntegrationTestWithMongoDB { .andDo(MockMvcResultPrinter.print()).andExpect(status().isNotModified()); // Now another deployment - final DistributionSet ds2 = TestDataUtil.generateDistributionSet("2", softwareManagement, - distributionSetManagement); + final DistributionSet ds2 = testdataFactory.createDistributionSet("2"); deploymentManagement.assignDistributionSet(ds2.getId(), new String[] { "4711" }); @@ -225,10 +228,10 @@ public class RootControllerTest extends AbstractIntegrationTestWithMongoDB { @Description("Ensures that the target state machine of a precomissioned target switches from " + "UNKNOWN to REGISTERED when the target polls for the first time.") public void rootRsPrecommissioned() throws Exception { - final Target target = new Target("4711"); + final Target target = entityFactory.generateTarget("4711"); targetManagement.createTarget(target); - assertThat(targetRepository.findByControllerId("4711").getTargetInfo().getUpdateStatus()) + assertThat(targetManagement.findTargetByControllerID("4711").getTargetInfo().getUpdateStatus()) .isEqualTo(TargetUpdateStatus.UNKNOWN); final long current = System.currentTimeMillis(); @@ -241,7 +244,7 @@ public class RootControllerTest extends AbstractIntegrationTestWithMongoDB { assertThat(targetManagement.findTargetByControllerID("4711").getTargetInfo().getLastTargetQuery()) .isGreaterThanOrEqualTo(current); - assertThat(targetRepository.findByControllerId("4711").getTargetInfo().getUpdateStatus()) + assertThat(targetManagement.findTargetByControllerID("4711").getTargetInfo().getUpdateStatus()) .isEqualTo(TargetUpdateStatus.REGISTERED); } @@ -259,16 +262,32 @@ public class RootControllerTest extends AbstractIntegrationTestWithMongoDB { } + @Test + @Description("Ensures that the source IP address of the polling target is not stored in repository if disabled") + public void rootRsIpAddressNotStoredIfDisabled() throws Exception { + securityProperties.getClients().setTrackRemoteIp(false); + + // test + final String knownControllerId1 = "0815"; + mvc.perform(get("/{tenant}/controller/v1/{controllerId}", tenantAware.getCurrentTenant(), knownControllerId1)) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); + + // verify + final Target target = targetManagement.findTargetByControllerID(knownControllerId1); + assertThat(target.getTargetInfo().getAddress()).isEqualTo(IpUtil.createHttpUri("***")); + + securityProperties.getClients().setTrackRemoteIp(true); + } + @Test @Description("Controller trys to finish an update process after it has been finished by an error action status.") public void tryToFinishAnUpdateProcessAfterItHasBeenFinished() throws Exception { // mock - final Target target = new Target("911"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final Target target = entityFactory.generateTarget("911"); + final DistributionSet ds = testdataFactory.createDistributionSet(""); Target savedTarget = targetManagement.createTarget(target); - final List toAssign = new ArrayList(); + final List toAssign = new ArrayList<>(); toAssign.add(savedTarget); savedTarget = deploymentManagement.assignDistributionSet(ds, toAssign).getAssignedEntity().iterator().next(); final Action savedAction = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); diff --git a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DosFilterTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DosFilterTest.java new file mode 100644 index 000000000..d63d9efc1 --- /dev/null +++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DosFilterTest.java @@ -0,0 +1,162 @@ +/** + * 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.ddi.rest.resource; + +import static org.fest.assertions.api.Assertions.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; +import org.eclipse.hawkbit.rest.util.JsonBuilder; +import org.junit.Test; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MvcResult; + +import com.google.common.net.HttpHeaders; + +import ru.yandex.qatools.allure.annotations.Description; +import ru.yandex.qatools.allure.annotations.Features; +import ru.yandex.qatools.allure.annotations.Stories; + +/** + * Test potential DOS attack scenarios and check if the filter prevents them. + * + */ +@ActiveProfiles({ "test" }) +@Features("Component Tests - REST Security") +@Stories("Denial of Service protection filter") +public class DosFilterTest extends AbstractRestIntegrationTest { + + @Test + @Description("Ensures that clients that are on the blacklist are forbidded ") + public void blackListedClientIsForbidden() throws Exception { + mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()) + .header(HttpHeaders.X_FORWARDED_FOR, "192.168.0.4 , 10.0.0.1 ")).andExpect(status().isForbidden()); + } + + @Test + @Description("Ensures that a READ DoS attempt is blocked ") + public void getFloddingAttackThatisPrevented() throws Exception { + + MvcResult result = null; + + int requests = 0; + do { + result = mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()) + .header(HttpHeaders.X_FORWARDED_FOR, "10.0.0.1")).andReturn(); + requests++; + + // we give up after 10.000 requests + assertThat(requests).isLessThan(10_000); + } while (result.getResponse().getStatus() != HttpStatus.TOO_MANY_REQUESTS.value()); + + // the filter shuts down after 100 GET requests + assertThat(requests).isGreaterThanOrEqualTo(100); + } + + @Test + @Description("Ensures that an assumed READ DoS attempt is not blocked as the client (with IPv4 address) is on a whitelist") + public void unacceptableGetLoadButOnWhitelistIPv4() throws Exception { + for (int i = 0; i < 1_000; i++) { + mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()) + .header(HttpHeaders.X_FORWARDED_FOR, "127.0.0.1")).andExpect(status().isOk()); + } + } + + @Test + @Description("Ensures that an assumed READ DoS attempt is not blocked as the client (with IPv6 address) is on a whitelist") + public void unacceptableGetLoadButOnWhitelistIPv6() throws Exception { + for (int i = 0; i < 1_000; i++) { + mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()) + .header(HttpHeaders.X_FORWARDED_FOR, "0:0:0:0:0:0:0:1")).andExpect(status().isOk()); + } + } + + @Test + @Description("Ensures that a relatively high number of READ requests is allowed if it is below the DoS detection threshold") + public void acceptableGetLoad() throws Exception { + + for (int x = 0; x < 3; x++) { + // sleep for one second + Thread.sleep(1100); + for (int i = 0; i < 99; i++) { + mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()) + .header(HttpHeaders.X_FORWARDED_FOR, "10.0.0.1")).andExpect(status().isOk()); + } + } + } + + @Test + @Description("Ensures that a WRITE DoS attempt is blocked ") + public void putPostFloddingAttackThatisPrevented() throws Exception { + final Long actionId = prepareDeploymentBase(); + final String feedback = JsonBuilder.deploymentActionFeedback(actionId.toString(), "proceeding"); + + MvcResult result = null; + int requests = 0; + do { + result = mvc.perform(post("/{tenant}/controller/v1/4711/deploymentBase/" + actionId + "/feedback", + tenantAware.getCurrentTenant()).header(HttpHeaders.X_FORWARDED_FOR, "10.0.0.1").content(feedback) + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) + .andReturn(); + requests++; + + // we give up after 500 requests + assertThat(requests).isLessThan(500); + } while (result.getResponse().getStatus() != HttpStatus.TOO_MANY_REQUESTS.value()); + + // the filter shuts down after 10 POST requests + assertThat(requests).isGreaterThanOrEqualTo(10); + + } + + @Test + @Description("Ensures that a relatively high number of WRITE requests is allowed if it is below the DoS detection threshold") + public void acceptablePutPostLoad() throws Exception { + final Long actionId = prepareDeploymentBase(); + final String feedback = JsonBuilder.deploymentActionFeedback(actionId.toString(), "proceeding"); + + for (int x = 0; x < 5; x++) { + // sleep for one second + Thread.sleep(1100); + + for (int i = 0; i < 9; i++) { + mvc.perform(post("/{tenant}/controller/v1/4711/deploymentBase/" + actionId + "/feedback", + tenantAware.getCurrentTenant()).header(HttpHeaders.X_FORWARDED_FOR, "10.0.0.1") + .content(feedback).contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } + } + } + + private Long prepareDeploymentBase() { + final DistributionSet ds = testdataFactory.createDistributionSet("test"); + final Target target = targetManagement.createTarget(entityFactory.generateTarget("4711")); + final List toAssign = new ArrayList<>(); + toAssign.add(target); + + final Iterable saved = deploymentManagement.assignDistributionSet(ds, toAssign).getAssignedEntity(); + assertThat(deploymentManagement.findActiveActionsByTarget(target)).hasSize(1); + + final Action uaction = deploymentManagement.findActiveActionsByTarget(target).get(0); + + return uaction.getId(); + } + +} diff --git a/hawkbit-repository/src/fbExcludeFilter.xml b/hawkbit-ddi-resource/src/test/resources/logback.xml similarity index 50% rename from hawkbit-repository/src/fbExcludeFilter.xml rename to hawkbit-ddi-resource/src/test/resources/logback.xml index bd85e5e73..447712338 100644 --- a/hawkbit-repository/src/fbExcludeFilter.xml +++ b/hawkbit-ddi-resource/src/test/resources/logback.xml @@ -1,3 +1,4 @@ + - - - - - \ No newline at end of file + + + + + + + + + + \ No newline at end of file diff --git a/hawkbit-dmf-amqp/pom.xml b/hawkbit-dmf-amqp/pom.xml index 127103b91..c2ed7c213 100644 --- a/hawkbit-dmf-amqp/pom.xml +++ b/hawkbit-dmf-amqp/pom.xml @@ -23,10 +23,10 @@ org.eclipse.hawkbit - hawkbit-repository + hawkbit-repository-api ${project.version} - + org.eclipse.hawkbit hawkbit-core ${project.version} @@ -41,6 +41,10 @@ hawkbit-dmf-api ${project.version} + + org.springframework.boot + spring-boot-autoconfigure + org.springframework.amqp spring-rabbit @@ -73,6 +77,12 @@ + + org.eclipse.hawkbit + hawkbit-repository-test + ${project.version} + test + com.h2database h2 @@ -90,9 +100,9 @@ org.eclipse.hawkbit - hawkbit-repository + hawkbit-repository-jpa ${project.version} - tests + test ru.yandex.qatools.allure diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java index 20a11713f..11f892654 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java @@ -8,21 +8,36 @@ */ package org.eclipse.hawkbit.amqp; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; + import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.FanoutExchange; import org.springframework.amqp.core.Queue; -import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.core.QueueBuilder; +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitAdmin; import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory; import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.amqp.RabbitProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.retry.backoff.ExponentialBackOffPolicy; +import org.springframework.retry.support.RetryTemplate;; /** * The spring AMQP configuration which is enabled by using the profile @@ -32,14 +47,65 @@ import org.springframework.context.annotation.Bean; @EnableConfigurationProperties({ AmqpProperties.class, AmqpDeadletterProperties.class }) public class AmqpConfiguration { - @Autowired - protected AmqpProperties amqpProperties; + private static final Logger LOGGER = LoggerFactory.getLogger(AmqpConfiguration.class); @Autowired - protected AmqpDeadletterProperties amqpDeadletterProperties; + private AmqpProperties amqpProperties; @Autowired - private ConnectionFactory connectionFactory; + private AmqpDeadletterProperties amqpDeadletterProperties; + + @Autowired + private ConnectionFactory rabbitConnectionFactory; + + @Configuration + @ConditionalOnMissingBean(ConnectionFactory.class) + protected static class RabbitConnectionFactoryCreator { + + @Autowired + private AmqpProperties amqpProperties; + + @Autowired + @Qualifier("asyncExecutor") + private Executor threadPoolExecutor; + + @Autowired + private ScheduledExecutorService scheduledExecutorService; + + /** + * {@link ConnectionFactory} with enabled publisher confirms and + * heartbeat. + * + * @param config + * with standard {@link RabbitProperties} + * @return {@link ConnectionFactory} + */ + @Bean + public ConnectionFactory rabbitConnectionFactory(final RabbitProperties config) { + final CachingConnectionFactory factory = new CachingConnectionFactory(); + factory.setRequestedHeartBeat(amqpProperties.getRequestedHeartBeat()); + factory.setExecutor(threadPoolExecutor); + factory.getRabbitConnectionFactory().setHeartbeatExecutor(scheduledExecutorService); + factory.setPublisherConfirms(true); + + final String addresses = config.getAddresses(); + factory.setAddresses(addresses); + if (config.getHost() != null) { + factory.setHost(config.getHost()); + factory.setPort(config.getPort()); + } + if (config.getUsername() != null) { + factory.setUsername(config.getUsername()); + } + if (config.getPassword() != null) { + factory.setPassword(config.getPassword()); + } + if (config.getVirtualHost() != null) { + factory.setVirtualHost(config.getVirtualHost()); + } + return factory; + } + } /** * Create a {@link RabbitAdmin} and ignore declaration exceptions. @@ -49,44 +115,101 @@ public class AmqpConfiguration { */ @Bean public RabbitAdmin rabbitAdmin() { - final RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory); + final RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitConnectionFactory); rabbitAdmin.setIgnoreDeclarationExceptions(true); return rabbitAdmin; } /** - * Method to set the Jackson2JsonMessageConverter. - * - * @return the Jackson2JsonMessageConverter + * @return {@link RabbitTemplate} with automatic retry, published confirms + * and {@link Jackson2JsonMessageConverter}. */ @Bean public RabbitTemplate rabbitTemplate() { - final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + final RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory); rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter()); + + final RetryTemplate retryTemplate = new RetryTemplate(); + retryTemplate.setBackOffPolicy(new ExponentialBackOffPolicy()); + rabbitTemplate.setRetryTemplate(retryTemplate); + + rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> { + if (ack) { + LOGGER.debug("Message with {} confirmed by broker.", correlationData); + } else { + LOGGER.error("Broker is unable to handle message with {} : {}", correlationData, cause); + } + }); + return rabbitTemplate; } /** - * Create the sp receiver queue. + * Create the DMF API receiver queue for retrieving DMF messages. * * @return the receiver queue */ @Bean - public Queue receiverQueue() { + public Queue dmfReceiverQueue() { return new Queue(amqpProperties.getReceiverQueue(), true, false, false, amqpDeadletterProperties.getDeadLetterExchangeArgs(amqpProperties.getDeadLetterExchange())); } /** - * Create the dead letter fanout exchange. + * Create the DMF API receiver queue for authentication requests called by + * 3rd party artifact storages for download authorization by devices. + * + * @return the receiver queue + */ + @Bean + public Queue authenticationReceiverQueue() { + return QueueBuilder.nonDurable(amqpProperties.getAuthenticationReceiverQueue()).autoDelete() + .withArguments(getTTLMaxArgsAuthenticationQueue()).build(); + } + + /** + * Create DMF exchange. * * @return the fanout exchange */ @Bean - public FanoutExchange senderExchange() { + public FanoutExchange dmfSenderExchange() { return new FanoutExchange(AmqpSettings.DMF_EXCHANGE); } + /** + * Create the Binding {@link AmqpConfiguration#dmfReceiverQueue()} to + * {@link AmqpConfiguration#dmfSenderExchange()}. + * + * @return the binding and create the queue and exchange + */ + @Bean + public Binding bindDmfSenderExchangeToDmfQueue() { + return BindingBuilder.bind(dmfReceiverQueue()).to(dmfSenderExchange()); + } + + /** + * Create authentication exchange. + * + * @return the fanout exchange + */ + @Bean + public FanoutExchange authenticationExchange() { + return new FanoutExchange(AmqpSettings.AUTHENTICATION_EXCHANGE, false, true); + } + + /** + * Create the Binding + * {@link AmqpConfiguration#authenticationReceiverQueue()} to + * {@link AmqpConfiguration#authenticationExchange()}. + * + * @return the binding and create the queue and exchange + */ + @Bean + public Binding bindAuthenticationSenderExchangeToAuthenticationQueue() { + return BindingBuilder.bind(authenticationReceiverQueue()).to(authenticationExchange()); + } + /** * Create dead letter queue. * @@ -103,29 +226,18 @@ public class AmqpConfiguration { * @return the fanout exchange */ @Bean - public FanoutExchange exchangeDeadLetter() { + public FanoutExchange deadLetterExchange() { return new FanoutExchange(amqpProperties.getDeadLetterExchange()); } /** - * Create the Binding deadLetterQueue to exchangeDeadLetter. + * Create the Binding deadLetterQueue to deadLetterExchange. * * @return the binding */ @Bean - public Binding bindDeadLetterQueueToLwm2mExchange() { - return BindingBuilder.bind(deadLetterQueue()).to(exchangeDeadLetter()); - } - - /** - * Create the Binding {@link AmqpConfiguration#receiverQueueFromSp()} to - * {@link AmqpConfiguration#senderConnectorToSpExchange()}. - * - * @return the binding and create the queue and exchange - */ - @Bean - public Binding bindSenderExchangeToSpQueue() { - return BindingBuilder.bind(receiverQueue()).to(senderExchange()); + public Binding bindDeadLetterQueueToDeadLetterExchange() { + return BindingBuilder.bind(deadLetterQueue()).to(deadLetterExchange()); } /** @@ -156,12 +268,15 @@ public class AmqpConfiguration { * AMQP messages */ @Bean(name = { "listenerContainerFactory" }) - public SimpleRabbitListenerContainerFactory listenerContainerFactory() { - final SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory(); - containerFactory.setDefaultRequeueRejected(false); - containerFactory.setConnectionFactory(connectionFactory); - containerFactory.setMissingQueuesFatal(amqpProperties.isMissingQueuesFatal()); - return containerFactory; + public RabbitListenerContainerFactory listenerContainerFactory() { + return new ConfigurableRabbitListenerContainerFactory(amqpProperties, rabbitConnectionFactory); + } + + private static Map getTTLMaxArgsAuthenticationQueue() { + final Map args = new HashMap<>(); + args.put("x-message-ttl", Duration.ofSeconds(30).toMillis()); + args.put("x-max-length", 1_000); + return args; } } 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 bbd7b6b48..b643be322 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 @@ -25,7 +25,7 @@ import org.eclipse.hawkbit.dmf.json.model.DownloadAndUpdateRequest; import org.eclipse.hawkbit.dmf.json.model.SoftwareModule; import org.eclipse.hawkbit.eventbus.EventSubscriber; import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent; -import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.util.IpUtil; import org.springframework.amqp.core.Message; @@ -114,7 +114,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { } - private MessageProperties createConnectorMessageProperties(final String tenant, final String controllerId, + private static MessageProperties createConnectorMessageProperties(final String tenant, final String controllerId, final EventTopic topic) { final MessageProperties messageProperties = createMessageProperties(); messageProperties.setHeader(MessageHeaderKey.TOPIC, topic); 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 7a452c603..d1bf85103 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 @@ -14,6 +14,7 @@ import java.util.Collections; import java.util.List; import java.util.UUID; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.eclipse.hawkbit.api.HostnameResolver; import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; @@ -30,12 +31,15 @@ import org.eclipse.hawkbit.dmf.json.model.ArtifactHash; import org.eclipse.hawkbit.dmf.json.model.DownloadResponse; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource; -import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ControllerManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.RepositoryConstants; +import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.TenantNotExistException; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.ActionStatus; @@ -43,9 +47,11 @@ import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.util.IpUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.amqp.AmqpRejectAndDontRequeueException; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.rabbit.annotation.RabbitListener; @@ -97,6 +103,12 @@ public class AmqpMessageHandlerService extends BaseAmqpService { @Autowired private HostnameResolver hostnameResolver; + @Autowired + private EntityFactory entityFactory; + + @Autowired + private SystemSecurityContext systemSecurityContext; + /** * Constructor. * @@ -107,29 +119,39 @@ public class AmqpMessageHandlerService extends BaseAmqpService { super(defaultTemplate); } - // Method is not unused. It is called by the spring rabbit listener. - @SuppressWarnings("squid:UnusedPrivateMethod") - @RabbitListener(queues = "${hawkbit.dmf.rabbitmq.receiverQueue}", containerFactory = "listenerContainerFactory") - private Message onMessage(final Message message, @Header(MessageHeaderKey.TYPE) final String type, - @Header(MessageHeaderKey.TENANT) final String tenant) { - return onMessage(message, type, tenant, getRabbitTemplate().getConnectionFactory().getVirtualHost()); - } - /** - * Method to handle all incoming amqp messages. + * Method to handle all incoming DMF amqp messages. * * @param message * incoming message * @param type * the message type - * @param contentType - * the contentType of the message * @param tenant * the contentType of the message - * @param virtualHost - * the virtual host + * * @return a message if no message is send back to sender */ + @RabbitListener(queues = "${hawkbit.dmf.rabbitmq.receiverQueue}", containerFactory = "listenerContainerFactory") + public Message onMessage(final Message message, @Header(MessageHeaderKey.TYPE) final String type, + @Header(MessageHeaderKey.TENANT) final String tenant) { + return onMessage(message, type, tenant, getRabbitTemplate().getConnectionFactory().getVirtualHost()); + } + + @RabbitListener(queues = "${hawkbit.dmf.rabbitmq.authenticationReceiverQueue}", containerFactory = "listenerContainerFactory") + public Message onAuthenticationRequest(final Message message) { + checkContentTypeJson(message); + final SecurityContext oldContext = SecurityContextHolder.getContext(); + try { + return handleAuthentifiactionMessage(message); + } catch (final IllegalArgumentException ex) { + throw new AmqpRejectAndDontRequeueException("Invalid message!", ex); + } catch (final TenantNotExistException teex) { + throw new AmqpRejectAndDontRequeueException(teex); + } finally { + SecurityContextHolder.setContext(oldContext); + } + } + public Message onMessage(final Message message, final String type, final String tenant, final String virtualHost) { checkContentTypeJson(message); final SecurityContext oldContext = SecurityContextHolder.getContext(); @@ -146,11 +168,13 @@ public class AmqpMessageHandlerService extends BaseAmqpService { final EventTopic eventTopic = EventTopic.valueOf(topicValue); handleIncomingEvent(message, eventTopic); break; - case AUTHENTIFICATION: - return handleAuthentifiactionMessage(message); default: logAndThrowMessageError(message, "No handle method was found for the given message type."); } + } catch (final IllegalArgumentException ex) { + throw new AmqpRejectAndDontRequeueException("Invalid message!", ex); + } catch (final TenantNotExistException teex) { + throw new AmqpRejectAndDontRequeueException(teex); } finally { SecurityContextHolder.setContext(oldContext); } @@ -306,9 +330,10 @@ public class AmqpMessageHandlerService extends BaseAmqpService { final DistributionSet distributionSet = action.getDistributionSet(); final List softwareModuleList = controllerManagement .findSoftwareModulesByDistributionSet(distributionSet); + final String targetSecurityToken = systemSecurityContext.runAsSystem(() -> target.getSecurityToken()); eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(), target.getControllerId(), action.getId(), softwareModuleList, target.getTargetInfo().getAddress(), - target.getSecurityToken())); + targetSecurityToken)); } @@ -338,11 +363,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService { final ActionUpdateStatus actionUpdateStatus = convertMessage(message, ActionUpdateStatus.class); final Action action = checkActionExist(message, actionUpdateStatus); - final ActionStatus actionStatus = new ActionStatus(); - actionUpdateStatus.getMessage().forEach(actionStatus::addMessage); - - actionStatus.setAction(action); - actionStatus.setOccurredAt(System.currentTimeMillis()); + final ActionStatus actionStatus = createActionStatus(message, actionUpdateStatus, action); switch (actionUpdateStatus.getActionStatus()) { case DOWNLOAD: @@ -373,18 +394,37 @@ public class AmqpMessageHandlerService extends BaseAmqpService { logAndThrowMessageError(message, "Status for action does not exisit."); } - final Action addUpdateActionStatus = getUpdateActionStatus(action, actionStatus); + final Action addUpdateActionStatus = getUpdateActionStatus(actionStatus); if (!addUpdateActionStatus.isActive()) { lookIfUpdateAvailable(action.getTarget()); } } - private Action getUpdateActionStatus(final Action action, final ActionStatus actionStatus) { - if (actionStatus.getStatus().equals(Status.CANCELED)) { - return controllerManagement.addCancelActionStatus(actionStatus, action); + private ActionStatus createActionStatus(final Message message, final ActionUpdateStatus actionUpdateStatus, + final Action action) { + final ActionStatus actionStatus = entityFactory.generateActionStatus(); + actionUpdateStatus.getMessage().forEach(actionStatus::addMessage); + + if (ArrayUtils.isNotEmpty(message.getMessageProperties().getCorrelationId())) { + actionStatus.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "DMF message correlation-id " + + convertCorrelationId(message)); } - return controllerManagement.addUpdateActionStatus(actionStatus, action); + + actionStatus.setAction(action); + actionStatus.setOccurredAt(System.currentTimeMillis()); + return actionStatus; + } + + private static String convertCorrelationId(final Message message) { + return new String(message.getMessageProperties().getCorrelationId()); + } + + private Action getUpdateActionStatus(final ActionStatus actionStatus) { + if (actionStatus.getStatus().equals(Status.CANCELED)) { + return controllerManagement.addCancelActionStatus(actionStatus); + } + return controllerManagement.addUpdateActionStatus(actionStatus); } private Action checkActionExist(final Message message, final ActionUpdateStatus actionUpdateStatus) { @@ -424,7 +464,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService { if (messageProperties.getContentType() != null && messageProperties.getContentType().contains("json")) { return; } - throw new IllegalArgumentException("Content-Type is not JSON compatible"); + throw new AmqpRejectAndDontRequeueException("Content-Type is not JSON compatible"); } void setControllerManagement(final ControllerManagement controllerManagement) { @@ -451,4 +491,11 @@ public class AmqpMessageHandlerService extends BaseAmqpService { this.eventBus = eventBus; } + void setEntityFactory(final EntityFactory entityFactory) { + this.entityFactory = entityFactory; + } + + void setSystemSecurityContext(final SystemSecurityContext systemSecurityContext) { + this.systemSecurityContext = systemSecurityContext; + } } diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java index ce6068ce8..56aa37772 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.amqp; +import java.util.concurrent.TimeUnit; + import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -29,14 +31,97 @@ public class AmqpProperties { private String deadLetterExchange = "dmf.connector.deadletter"; /** - * DMF API receiving queue. + * DMF API receiving queue for EVENT or THING_CREATED message. */ private String receiverQueue = "dmf_receiver"; + /** + * Authentication request called by 3rd party artifact storages for download + * authorizations. + */ + private String authenticationReceiverQueue = "authentication_receiver"; + /** * Missing queue fatal. */ - private boolean missingQueuesFatal = false; + private boolean missingQueuesFatal; + + /** + * Requested heartbeat interval from broker in {@link TimeUnit#SECONDS}. + */ + private int requestedHeartBeat = (int) TimeUnit.SECONDS.toSeconds(60); + + /** + * Sets an upper limit to the number of consumers. + */ + private int maxConcurrentConsumers = 10; + + /** + * Tells the broker how many messages to send to each consumer in a single + * request. Often this can be set quite high to improve throughput. + */ + private int prefetchCount = 10; + + /** + * Initial number of consumers. Is scaled up if necessary up to + * {@link #maxConcurrentConsumers}. + */ + private int initialConcurrentConsumers = 3; + + /** + * The number of retry attempts when passive queue declaration fails. + * Passive queue declaration occurs when the consumer starts or, when + * consuming from multiple queues, when not all queues were available during + * initialization. + */ + private int declarationRetries = 50; + + /** + * @return the declarationRetries + */ + public int getDeclarationRetries() { + return declarationRetries; + } + + /** + * @param declarationRetries + * the declarationRetries to set + */ + public void setDeclarationRetries(final int declarationRetries) { + this.declarationRetries = declarationRetries; + } + + public String getAuthenticationReceiverQueue() { + return authenticationReceiverQueue; + } + + public void setAuthenticationReceiverQueue(final String authenticationReceiverQueue) { + this.authenticationReceiverQueue = authenticationReceiverQueue; + } + + public int getPrefetchCount() { + return prefetchCount; + } + + public void setPrefetchCount(final int prefetchCount) { + this.prefetchCount = prefetchCount; + } + + public int getInitialConcurrentConsumers() { + return initialConcurrentConsumers; + } + + public void setInitialConcurrentConsumers(final int initialConcurrentConsumers) { + this.initialConcurrentConsumers = initialConcurrentConsumers; + } + + public int getMaxConcurrentConsumers() { + return maxConcurrentConsumers; + } + + public void setMaxConcurrentConsumers(final int maxConcurrentConsumers) { + this.maxConcurrentConsumers = maxConcurrentConsumers; + } /** * Is missingQueuesFatal enabled @@ -99,7 +184,16 @@ public class AmqpProperties { return receiverQueue; } + public int getRequestedHeartBeat() { + return requestedHeartBeat; + } + + public void setRequestedHeartBeat(final int requestedHeartBeat) { + this.requestedHeartBeat = requestedHeartBeat; + } + public void setReceiverQueue(final String receiverQueue) { this.receiverQueue = receiverQueue; } + } diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java index 3c5b78e01..1d9693ed7 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java @@ -15,6 +15,7 @@ import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.amqp.AmqpRejectAndDontRequeueException; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.AbstractJavaTypeMapper; @@ -99,8 +100,8 @@ public class BaseAmqpService { } protected final void logAndThrowMessageError(final Message message, final String error) { - LOGGER.warn("Error \"{}\" reported by message: {}", error, message); - throw new IllegalArgumentException(error); + LOGGER.warn("Warning! \"{}\" reported by message: {}", error, message); + throw new AmqpRejectAndDontRequeueException(error); } protected RabbitTemplate getRabbitTemplate() { diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/ConfigurableRabbitListenerContainerFactory.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/ConfigurableRabbitListenerContainerFactory.java new file mode 100644 index 000000000..14e6f8fcb --- /dev/null +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/ConfigurableRabbitListenerContainerFactory.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.amqp; + +import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; + +/** + * {@link RabbitListenerContainerFactory} that can be configured through + * hawkBit's {@link AmqpProperties}. + * + */ +public class ConfigurableRabbitListenerContainerFactory extends SimpleRabbitListenerContainerFactory { + private final AmqpProperties amqpProperties; + + /** + * Constructor. + * + * @param rabbitConnectionFactory + * for the container factory + * @param amqpProperties + * to configure the container factory + */ + public ConfigurableRabbitListenerContainerFactory(final AmqpProperties amqpProperties, + final ConnectionFactory rabbitConnectionFactory) { + this.amqpProperties = amqpProperties; + setDefaultRequeueRejected(true); + setConnectionFactory(rabbitConnectionFactory); + setMissingQueuesFatal(amqpProperties.isMissingQueuesFatal()); + setConcurrentConsumers(amqpProperties.getInitialConcurrentConsumers()); + setMaxConcurrentConsumers(amqpProperties.getMaxConcurrentConsumers()); + setPrefetchCount(amqpProperties.getPrefetchCount()); + + } + + @Override + // Exception squid:UnusedProtectedMethod - called by + // AbstractRabbitListenerContainerFactory + @SuppressWarnings("squid:UnusedProtectedMethod") + protected void initializeContainer(final SimpleMessageListenerContainer instance) { + super.initializeContainer(instance); + instance.setDeclarationRetries(amqpProperties.getDeclarationRetries()); + } +} diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpSenderService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpSenderService.java index 244544b64..d951cce5d 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpSenderService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpSenderService.java @@ -9,10 +9,14 @@ package org.eclipse.hawkbit.amqp; import java.net.URI; +import java.util.UUID; import org.eclipse.hawkbit.util.IpUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.support.CorrelationData; /** * A default implementation for the sender service. The service sends all amqp @@ -20,6 +24,7 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate; * extracted from the uri. */ public class DefaultAmqpSenderService implements AmqpSenderService { + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAmqpSenderService.class); private final RabbitTemplate internalAmqpTemplate; @@ -39,7 +44,17 @@ public class DefaultAmqpSenderService implements AmqpSenderService { return; } - internalAmqpTemplate.send(extractExchange(replyTo), null, message); + final String correlationId = UUID.randomUUID().toString(); + final String exchange = extractExchange(replyTo); + message.getMessageProperties().setCorrelationId(correlationId.getBytes()); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Sending message {} to exchange {} with correlationId {}", message, exchange, correlationId); + } else { + LOGGER.debug("Sending message to exchange {} with correlationId {}", exchange, correlationId); + } + + internalAmqpTemplate.send(exchange, null, message, new CorrelationData(correlationId)); } } diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/AmqpTestConfiguration.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/AmqpTestConfiguration.java index a1dd54710..467c650be 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/AmqpTestConfiguration.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/AmqpTestConfiguration.java @@ -8,20 +8,48 @@ */ package org.eclipse.hawkbit; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.eclipse.hawkbit.amqp.AmqpProperties; import org.eclipse.hawkbit.amqp.AmqpSenderService; import org.eclipse.hawkbit.amqp.DefaultAmqpSenderService; +import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder; +import org.eclipse.hawkbit.security.SystemSecurityContext; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; /** * */ @Configuration +@EnableConfigurationProperties({ AmqpProperties.class }) public class AmqpTestConfiguration { + /** + * @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(); + } /** * Method to set the Jackson2JsonMessageConverter. @@ -45,4 +73,54 @@ public class AmqpTestConfiguration { public AmqpSenderService amqpSenderServiceBean(final RabbitTemplate rabbitTemplate) { return new DefaultAmqpSenderService(rabbitTemplate); } + + /** + * @return ExecutorService with security context availability in thread + * execution.. + */ + @Bean(destroyMethod = "shutdown") + @ConditionalOnMissingBean + public Executor asyncExecutor() { + return new DelegatingSecurityContextExecutorService(threadPoolExecutor()); + } + + /** + * @return central ThreadPoolExecutor for general purpose multi threaded + * operations. Tries an orderly shutdown when destroyed. + */ + private ThreadPoolExecutor threadPoolExecutor() { + final BlockingQueue blockingQueue = new ArrayBlockingQueue<>(10); + final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 10, 1000, TimeUnit.MILLISECONDS, + blockingQueue, new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build()); + + return threadPoolExecutor; + } + + /** + * @return {@link TaskExecutor} for task execution + */ + @Bean + @ConditionalOnMissingBean + public TaskExecutor taskExecutor() { + return new ConcurrentTaskExecutor(asyncExecutor()); + } + + /** + * @return {@link ScheduledExecutorService} based on + * {@link #threadPoolTaskScheduler()}. + */ + @Bean + @ConditionalOnMissingBean + public ScheduledExecutorService scheduledExecutorService() { + return threadPoolTaskScheduler().getScheduledExecutor(); + } + + /** + * @return {@link ThreadPoolTaskScheduler} for scheduled operations. + */ + @Bean + @ConditionalOnMissingBean + public ThreadPoolTaskScheduler threadPoolTaskScheduler() { + return new ThreadPoolTaskScheduler(); + } } diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java index 898647bc6..211ac26a2 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java @@ -158,7 +158,7 @@ public class AmqpControllerAuthenticationTest { @Test @Description("Tests authentication message without principal") public void testAuthenticationMessageBadCredantialsWithoutPricipal() { - final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); + final MessageProperties messageProperties = createMessageProperties(null); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID, FileResource.createFileResourceBySha1("12345")); @@ -166,8 +166,7 @@ public class AmqpControllerAuthenticationTest { messageProperties); // test - final Message onMessage = amqpMessageHandlerService.onMessage(message, MessageType.AUTHENTIFICATION.name(), - TENANT, "vHost"); + final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message); // verify final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage); @@ -178,7 +177,7 @@ public class AmqpControllerAuthenticationTest { @Test @Description("Tests authentication message without wrong credential") public void testAuthenticationMessageBadCredantialsWithWrongCredential() { - final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); + final MessageProperties messageProperties = createMessageProperties(null); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID, FileResource.createFileResourceBySha1("12345")); when(tenantConfigurationManagement.getConfigurationValue( @@ -189,8 +188,7 @@ public class AmqpControllerAuthenticationTest { messageProperties); // test - final Message onMessage = amqpMessageHandlerService.onMessage(message, MessageType.AUTHENTIFICATION.name(), - TENANT, "vHost"); + final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message); // verify final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage); @@ -201,7 +199,7 @@ public class AmqpControllerAuthenticationTest { @Test @Description("Tests authentication message successfull") public void testSuccessfullMessageAuthentication() { - final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); + final MessageProperties messageProperties = createMessageProperties(null); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID, FileResource.createFileResourceBySha1("12345")); when(tenantConfigurationManagement.getConfigurationValue( @@ -212,8 +210,7 @@ public class AmqpControllerAuthenticationTest { messageProperties); // test - final Message onMessage = amqpMessageHandlerService.onMessage(message, MessageType.AUTHENTIFICATION.name(), - TENANT, "vHost"); + final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message); // verify final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage); @@ -232,7 +229,9 @@ public class AmqpControllerAuthenticationTest { private MessageProperties createMessageProperties(final MessageType type, final String replyTo) { final MessageProperties messageProperties = new MessageProperties(); - messageProperties.setHeader(MessageHeaderKey.TYPE, type.name()); + if (type != null) { + messageProperties.setHeader(MessageHeaderKey.TYPE, type.name()); + } messageProperties.setHeader(MessageHeaderKey.TENANT, TENANT); messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON); messageProperties.setReplyTo(replyTo); 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 c5cea9e05..103dc6c57 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 @@ -25,8 +25,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; -import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.api.ArtifactUrlHandler; import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; import org.eclipse.hawkbit.dmf.amqp.api.EventTopic; @@ -34,11 +32,12 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey; import org.eclipse.hawkbit.dmf.amqp.api.MessageType; import org.eclipse.hawkbit.dmf.json.model.DownloadAndUpdateRequest; import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent; -import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB; import org.eclipse.hawkbit.util.IpUtil; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -48,6 +47,7 @@ import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.AbstractJavaTypeMapper; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.ActiveProfiles; import ru.yandex.qatools.allure.annotations.Description; @@ -57,6 +57,7 @@ import ru.yandex.qatools.allure.annotations.Stories; @ActiveProfiles({ "test" }) @Features("Component Tests - Device Management Federation API") @Stories("AmqpMessage Dispatcher Service Test") +@SpringApplicationConfiguration(classes = { org.eclipse.hawkbit.RepositoryApplicationConfiguration.class }) public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWithMongoDB { private static final String TENANT = "default"; @@ -100,6 +101,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent); final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress()); final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); + assertThat(downloadAndUpdateRequest.getTargetSecurityToken()).isEqualTo(TEST_TOKEN); assertTrue("No softwaremmodule should be contained in the request", downloadAndUpdateRequest.getSoftwareModules().isEmpty()); } @@ -107,8 +109,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit @Test @Description("Verfies that download and install event with 3 software moduls and no artifacts works") public void testSendDownloadRequesWithSoftwareModulesAndNoArtifacts() { - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent( 1L, TENANT, CONTROLLER_ID, 1L, dsA.getModules(), AMQP_URI, TEST_TOKEN); amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent); @@ -116,6 +117,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); assertEquals("Expecting a size of 3 software modules in the reuqest", 3, downloadAndUpdateRequest.getSoftwareModules().size()); + assertThat(downloadAndUpdateRequest.getTargetSecurityToken()).isEqualTo(TEST_TOKEN); for (final org.eclipse.hawkbit.dmf.json.model.SoftwareModule softwareModule : downloadAndUpdateRequest .getSoftwareModules()) { assertTrue("Artifact list for softwaremodule should be empty", softwareModule.getArtifacts().isEmpty()); @@ -137,11 +139,10 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit @Test @Description("Verfies that download and install event with software moduls and artifacts works") public void testSendDownloadRequest() { - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); final SoftwareModule module = dsA.getModules().iterator().next(); final List receivedList = new ArrayList<>(); - for (final Artifact artifact : TestDataUtil.generateArtifacts(artifactManagement, module.getId())) { + for (final Artifact artifact : testdataFactory.createLocalArtifacts(module.getId())) { module.addArtifact((LocalArtifact) artifact); receivedList.add(new DbArtifact()); } @@ -155,6 +156,8 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); assertEquals("DownloadAndUpdateRequest event should contains 3 software modules", 3, downloadAndUpdateRequest.getSoftwareModules().size()); + assertThat(downloadAndUpdateRequest.getTargetSecurityToken()).isEqualTo(TEST_TOKEN); + for (final org.eclipse.hawkbit.dmf.json.model.SoftwareModule softwareModule : downloadAndUpdateRequest .getSoftwareModules()) { if (!softwareModule.getModuleId().equals(module.getId())) { 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 bfa47455b..7a3915e28 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 @@ -36,17 +36,23 @@ import org.eclipse.hawkbit.dmf.json.model.ActionUpdateStatus; import org.eclipse.hawkbit.dmf.json.model.DownloadResponse; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource; -import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ControllerManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.helper.SecurityTokenGeneratorHolder; +import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.security.SecurityTokenGenerator; +import org.eclipse.hawkbit.security.SystemSecurityContext; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -54,6 +60,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.amqp.AmqpRejectAndDontRequeueException; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.rabbit.core.RabbitTemplate; @@ -82,6 +89,9 @@ public class AmqpMessageHandlerServiceTest { @Mock private ControllerManagement controllerManagementMock; + @Mock + private EntityFactory entityFactoryMock; + @Mock private ArtifactManagement artifactManagementMock; @@ -103,6 +113,9 @@ public class AmqpMessageHandlerServiceTest { @Mock private RabbitTemplate rabbitTemplate; + @Mock + private SystemSecurityContext systemSecurityContextMock; + @Before public void before() throws Exception { messageConverter = new Jackson2JsonMessageConverter(); @@ -114,6 +127,8 @@ public class AmqpMessageHandlerServiceTest { amqpMessageHandlerService.setCache(cacheMock); amqpMessageHandlerService.setHostnameResolver(hostnameResolverMock); amqpMessageHandlerService.setEventBus(eventBus); + amqpMessageHandlerService.setEntityFactory(entityFactoryMock); + amqpMessageHandlerService.setSystemSecurityContext(systemSecurityContextMock); } @@ -125,8 +140,8 @@ public class AmqpMessageHandlerServiceTest { final Message message = new Message(new byte[0], messageProperties); try { amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, "vHost"); - fail("IllegalArgumentException was excepeted due to worng content type"); - } catch (final IllegalArgumentException e) { + fail("AmqpRejectAndDontRequeueException was excepeted due to worng content type"); + } catch (final AmqpRejectAndDontRequeueException e) { } } @@ -160,8 +175,8 @@ public class AmqpMessageHandlerServiceTest { try { amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, "vHost"); - fail("IllegalArgumentException was excepeted since no replyTo header was set"); - } catch (final IllegalArgumentException exception) { + fail("AmqpRejectAndDontRequeueException was excepeted since no replyTo header was set"); + } catch (final AmqpRejectAndDontRequeueException exception) { // test ok - exception was excepted } @@ -174,8 +189,8 @@ public class AmqpMessageHandlerServiceTest { final Message message = messageConverter.toMessage(new byte[0], messageProperties); try { amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, "vHost"); - fail("IllegalArgumentException was excepeted since no thingID was set"); - } catch (final IllegalArgumentException exception) { + fail("AmqpRejectAndDontRequeueException was excepeted since no thingID was set"); + } catch (final AmqpRejectAndDontRequeueException exception) { // test ok - exception was excepted } } @@ -190,8 +205,8 @@ public class AmqpMessageHandlerServiceTest { try { amqpMessageHandlerService.onMessage(message, type, TENANT, "vHost"); - fail("IllegalArgumentException was excepeted due to unknown message type"); - } catch (final IllegalArgumentException exception) { + fail("AmqpRejectAndDontRequeueException was excepeted due to unknown message type"); + } catch (final AmqpRejectAndDontRequeueException exception) { // test ok - exception was excepted } } @@ -203,22 +218,22 @@ public class AmqpMessageHandlerServiceTest { final Message message = new Message(new byte[0], messageProperties); try { amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); - fail("IllegalArgumentException was excepeted due to unknown message type"); - } catch (final IllegalArgumentException e) { + fail("AmqpRejectAndDontRequeueException was excepeted due to unknown message type"); + } catch (final AmqpRejectAndDontRequeueException e) { } try { messageProperties.setHeader(MessageHeaderKey.TOPIC, "wrongTopic"); amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); - fail("IllegalArgumentException was excepeted due to unknown topic"); - } catch (final IllegalArgumentException e) { + fail("AmqpRejectAndDontRequeueException was excepeted due to unknown topic"); + } catch (final AmqpRejectAndDontRequeueException e) { } messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.CANCEL_DOWNLOAD.name()); try { amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); - fail("IllegalArgumentException was excepeted because there was no event topic"); - } catch (final IllegalArgumentException exception) { + fail("AmqpRejectAndDontRequeueException was excepeted because there was no event topic"); + } catch (final AmqpRejectAndDontRequeueException exception) { // test ok - exception was excepted } @@ -236,8 +251,8 @@ public class AmqpMessageHandlerServiceTest { try { amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); - fail("IllegalArgumentException was excepeted since no action id was set"); - } catch (final IllegalArgumentException exception) { + fail("AmqpRejectAndDontRequeueException was excepeted since no action id was set"); + } catch (final AmqpRejectAndDontRequeueException exception) { // test ok - exception was excepted } } @@ -253,8 +268,8 @@ public class AmqpMessageHandlerServiceTest { try { amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); - fail("IllegalArgumentException was excepeted since no action id was set"); - } catch (final IllegalArgumentException exception) { + fail("AmqpRejectAndDontRequeueException was excepeted since no action id was set"); + } catch (final AmqpRejectAndDontRequeueException exception) { // test ok - exception was excepted } @@ -263,14 +278,14 @@ public class AmqpMessageHandlerServiceTest { @Test @Description("Tests that an download request is denied for an artifact which does not exists") public void authenticationRequestDeniedForArtifactWhichDoesNotExists() { - final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); - final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", FileResource.createFileResourceBySha1("12345")); + final MessageProperties messageProperties = createMessageProperties(null); + final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", + FileResource.createFileResourceBySha1("12345")); final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, messageProperties); // test - final Message onMessage = amqpMessageHandlerService.onMessage(message, MessageType.AUTHENTIFICATION.name(), - TENANT, "vHost"); + final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message); // verify final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage); @@ -282,8 +297,9 @@ public class AmqpMessageHandlerServiceTest { @Test @Description("Tests that an download request is denied for an artifact which is not assigned to the requested target") public void authenticationRequestDeniedForArtifactWhichIsNotAssignedToTarget() { - final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); - final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", FileResource.createFileResourceBySha1("12345")); + final MessageProperties messageProperties = createMessageProperties(null); + final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", + FileResource.createFileResourceBySha1("12345")); final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, messageProperties); @@ -293,8 +309,7 @@ public class AmqpMessageHandlerServiceTest { .thenThrow(EntityNotFoundException.class); // test - final Message onMessage = amqpMessageHandlerService.onMessage(message, MessageType.AUTHENTIFICATION.name(), - TENANT, "vHost"); + final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message); // verify final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage); @@ -306,8 +321,9 @@ public class AmqpMessageHandlerServiceTest { @Test @Description("Tests that an download request is allowed for an artifact which exists and assigned to the requested target") public void authenticationRequestAllowedForArtifactWhichExistsAndAssignedToTarget() throws MalformedURLException { - final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); - final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", FileResource.createFileResourceBySha1("12345")); + final MessageProperties messageProperties = createMessageProperties(null); + final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", + FileResource.createFileResourceBySha1("12345")); final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, messageProperties); @@ -324,8 +340,7 @@ public class AmqpMessageHandlerServiceTest { when(hostnameResolverMock.resolveHostname()).thenReturn(new URL("http://localhost")); // test - final Message onMessage = amqpMessageHandlerService.onMessage(message, MessageType.AUTHENTIFICATION.name(), - TENANT, "vHost"); + final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message); // verify final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage); @@ -346,7 +361,8 @@ public class AmqpMessageHandlerServiceTest { // Mock final Action action = createActionWithTarget(22L, Status.FINISHED); when(controllerManagementMock.findActionWithDetails(Matchers.any())).thenReturn(action); - when(controllerManagementMock.addUpdateActionStatus(Matchers.any(), Matchers.any())).thenReturn(action); + when(controllerManagementMock.addUpdateActionStatus(Matchers.any())).thenReturn(action); + when(entityFactoryMock.generateActionStatus()).thenReturn(new JpaActionStatus()); // for the test the same action can be used final List actionList = new ArrayList<>(); actionList.add(action); @@ -356,6 +372,8 @@ public class AmqpMessageHandlerServiceTest { when(controllerManagementMock.findSoftwareModulesByDistributionSet(Matchers.any())) .thenReturn(softwareModuleList); + when(systemSecurityContextMock.runAsSystem(anyObject())).thenReturn("securityToken"); + final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); final ActionUpdateStatus actionUpdateStatus = createActionUpdateStatus(ActionStatus.FINISHED, 23L); @@ -400,7 +418,9 @@ public class AmqpMessageHandlerServiceTest { private MessageProperties createMessageProperties(final MessageType type, final String replyTo) { final MessageProperties messageProperties = new MessageProperties(); - messageProperties.setHeader(MessageHeaderKey.TYPE, type.name()); + if (type != null) { + messageProperties.setHeader(MessageHeaderKey.TYPE, type.name()); + } messageProperties.setHeader(MessageHeaderKey.TENANT, TENANT); messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON); messageProperties.setReplyTo(replyTo); @@ -409,7 +429,7 @@ public class AmqpMessageHandlerServiceTest { private List createSoftwareModuleList() { final List softwareModuleList = new ArrayList<>(); - final SoftwareModule softwareModule = new SoftwareModule(); + final JpaSoftwareModule softwareModule = new JpaSoftwareModule(); softwareModule.setId(777L); softwareModuleList.add(softwareModule); return softwareModuleList; @@ -420,14 +440,18 @@ public class AmqpMessageHandlerServiceTest { initalizeSecurityTokenGenerator(); // Mock - final Action action = new Action(); - action.setId(targetId); - action.setStatus(status); - action.setTenant("DEFAULT"); - final Target target = new Target("target1"); - action.setTarget(target); - - return action; + final JpaAction actionMock = mock(JpaAction.class); + final JpaTarget targetMock = mock(JpaTarget.class); + final TargetInfo targetInfoMock = mock(TargetInfo.class); + when(actionMock.getId()).thenReturn(targetId); + when(actionMock.getStatus()).thenReturn(status); + when(actionMock.getTenant()).thenReturn("DEFAULT"); + when(actionMock.getTarget()).thenReturn(targetMock); + when(targetMock.getControllerId()).thenReturn("target1"); + when(targetMock.getSecurityToken()).thenReturn("securityToken"); + when(targetMock.getTargetInfo()).thenReturn(targetInfoMock); + when(targetInfoMock.getAddress()).thenReturn(null); + return actionMock; } private void initalizeSecurityTokenGenerator() throws IllegalAccessException { diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java index bfc560c38..8cd92d2bd 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java @@ -10,17 +10,13 @@ package org.eclipse.hawkbit.util; import static org.junit.Assert.assertEquals; -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; import org.eclipse.hawkbit.AmqpTestConfiguration; -import org.eclipse.hawkbit.RepositoryApplicationConfiguration; -import org.eclipse.hawkbit.TestConfiguration; -import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.api.ArtifactUrlHandler; import org.eclipse.hawkbit.api.UrlProtocol; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.tenancy.TenantAware; +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -35,27 +31,27 @@ import ru.yandex.qatools.allure.annotations.Stories; */ @Features("Component Tests - Artifact URL Handler") @Stories("Test to generate the artifact download URL") -@SpringApplicationConfiguration(classes = { RepositoryApplicationConfiguration.class, TestConfiguration.class, - AmqpTestConfiguration.class }) +@SpringApplicationConfiguration(classes = { AmqpTestConfiguration.class, + org.eclipse.hawkbit.RepositoryApplicationConfiguration.class }) public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTestWithMongoDB { + private static final String HTTPS_LOCALHOST = "https://localhost:8080/"; + private static final String HTTP_LOCALHOST = "http://localhost:8080/"; + @Autowired private ArtifactUrlHandler urlHandlerProperties; - @Autowired - private TenantAware tenantAware; + private LocalArtifact localArtifact; - private final String controllerId = "Test"; + private static final String CONTROLLER_ID = "Test"; private String fileName; private Long softwareModuleId; private String sha1Hash; @Before public void setup() { - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); final SoftwareModule module = dsA.getModules().iterator().next(); - localArtifact = (LocalArtifact) TestDataUtil.generateArtifacts(artifactManagement, module.getId()).stream() - .findAny().get(); + localArtifact = testdataFactory.createLocalArtifacts(module.getId()).stream().findAny().get(); softwareModuleId = localArtifact.getSoftwareModule().getId(); fileName = localArtifact.getFilename(); sha1Hash = localArtifact.getSha1Hash(); @@ -66,10 +62,10 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest @Description("Tests the generation of http download url.") public void testHttpUrl() { - final String url = urlHandlerProperties.getUrl(controllerId, softwareModuleId, fileName, sha1Hash, + final String url = urlHandlerProperties.getUrl(CONTROLLER_ID, softwareModuleId, fileName, sha1Hash, UrlProtocol.HTTP); assertEquals("http is build incorrect", - "http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId + HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + CONTROLLER_ID + "/softwaremodules/" + localArtifact.getSoftwareModule().getId() + "/artifacts/" + localArtifact.getFilename(), url); @@ -78,10 +74,10 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest @Test @Description("Tests the generation of https download url.") public void testHttpsUrl() { - final String url = urlHandlerProperties.getUrl(controllerId, softwareModuleId, fileName, sha1Hash, + final String url = urlHandlerProperties.getUrl(CONTROLLER_ID, softwareModuleId, fileName, sha1Hash, UrlProtocol.HTTPS); assertEquals("https is build incorrect", - "https://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId + HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + CONTROLLER_ID + "/softwaremodules/" + localArtifact.getSoftwareModule().getId() + "/artifacts/" + localArtifact.getFilename(), url); @@ -90,10 +86,10 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest @Test @Description("Tests the generation of coap download url.") public void testCoapUrl() { - final String url = urlHandlerProperties.getUrl(controllerId, softwareModuleId, fileName, sha1Hash, + final String url = urlHandlerProperties.getUrl(CONTROLLER_ID, softwareModuleId, fileName, sha1Hash, UrlProtocol.COAP); assertEquals("coap is build incorrect", "coap://127.0.0.1:5683/fw/" + tenantAware.getCurrentTenant() + "/" - + controllerId + "/sha1/" + localArtifact.getSha1Hash(), url); + + CONTROLLER_ID + "/sha1/" + localArtifact.getSha1Hash(), url); } } diff --git a/hawkbit-dmf-amqp/src/test/resources/application-test.properties b/hawkbit-dmf-amqp/src/test/resources/application-test.properties new file mode 100644 index 000000000..79b1fe78f --- /dev/null +++ b/hawkbit-dmf-amqp/src/test/resources/application-test.properties @@ -0,0 +1,38 @@ +# +# 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 +# + + + +# supported: H2, MYSQL +hawkbit.server.database=H2 + +spring.jpa.database=${hawkbit.server.database} + + +flyway.sqlMigrationSuffix=${spring.jpa.database}.sql + +# effective DB setting +spring.datasource.url=${${hawkbit.server.database}.spring.datasource.url} +spring.datasource.driverClassName=${${hawkbit.server.database}.spring.datasource.driverClassName} +spring.datasource.username=${${hawkbit.server.database}.spring.datasource.username} +spring.datasource.password=${${hawkbit.server.database}.spring.datasource.password} + +# H2 +##;AUTOCOMMIT=ON +H2.spring.datasource.url=jdbc:h2:mem:sp-db;DB_CLOSE_ON_EXIT=FALSE +#H2.spring.datasource.url=jdbc:h2:./db/sp-db;AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=FALSE;MVCC=TRUE +H2.spring.datasource.driverClassName=org.h2.Driver +H2.spring.datasource.username=sa +H2.spring.datasource.password=sa + +# MYSQL +MYSQL.spring.datasource.url=jdbc:mysql://localhost:3306/sp_test +MYSQL.spring.datasource.driverClassName=org.mariadb.jdbc.Driver +MYSQL.spring.datasource.username=root +MYSQL.spring.datasource.password= diff --git a/hawkbit-dmf-amqp/src/test/resources/logback.xml b/hawkbit-dmf-amqp/src/test/resources/logback.xml new file mode 100644 index 000000000..30060d1c6 --- /dev/null +++ b/hawkbit-dmf-amqp/src/test/resources/logback.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/amqp/api/AmqpSettings.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/amqp/api/AmqpSettings.java index 40ba04419..364f36aa5 100644 --- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/amqp/api/AmqpSettings.java +++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/amqp/api/AmqpSettings.java @@ -18,6 +18,8 @@ public final class AmqpSettings { public static final String DMF_EXCHANGE = "dmf.exchange"; + public static final String AUTHENTICATION_EXCHANGE = "authentication.exchange"; + private AmqpSettings() { } diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/amqp/api/MessageType.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/amqp/api/MessageType.java index 8cca32b06..e66a0c8c6 100644 --- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/amqp/api/MessageType.java +++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/amqp/api/MessageType.java @@ -26,9 +26,4 @@ public enum MessageType { */ THING_CREATED, - /** - * The authentication type. - */ - AUTHENTIFICATION, - } diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ActionStatus.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ActionStatus.java index c31ab83f3..2c38a771c 100644 --- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ActionStatus.java +++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ActionStatus.java @@ -21,6 +21,43 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public enum ActionStatus { + /** + * Action requests download by this target which has now started. + */ + DOWNLOAD, - DOWNLOAD, RETRIEVED, RUNNING, FINISHED, ERROR, WARNING, CANCELED, CANCEL_REJECTED; + /** + * Action has been send to the target. + */ + RETRIEVED, + + /** + * Action is still running for this target. + */ + RUNNING, + + /** + * Action is finished successfully for this target. + */ + FINISHED, + + /** + * Action has failed for this target. + */ + ERROR, + + /** + * Action is still running but with warnings. + */ + WARNING, + + /** + * Action has been canceled for this target. + */ + CANCELED, + + /** + * Cancellation has been rejected by the target.. + */ + CANCEL_REJECTED; } diff --git a/hawkbit-http-security/pom.xml b/hawkbit-http-security/pom.xml index a9b8a4080..bb77df454 100644 --- a/hawkbit-http-security/pom.xml +++ b/hawkbit-http-security/pom.xml @@ -22,7 +22,7 @@ org.eclipse.hawkbit - hawkbit-repository + hawkbit-repository-api ${project.version} diff --git a/hawkbit-mgmt-api/README.md b/hawkbit-mgmt-api/README.md new file mode 100644 index 000000000..eeb51c145 --- /dev/null +++ b/hawkbit-mgmt-api/README.md @@ -0,0 +1,14 @@ +# Eclipse.IoT hawkBit - Mgmt API + +This Management (Mgmt) API is used to manage and monitor the HawkBit Update Server via HTTP. This API allows Create/Read/Update/Delete operations for provisioning targets (i.e. devices) and repository content (i.e. software). + + +# Compile + +#### Build hawkbit-mgmt-api + +``` +$ cd hawkbit/hawkbit-mgmt-api +$ mvn clean install +``` + diff --git a/hawkbit-rest-api/pom.xml b/hawkbit-mgmt-api/pom.xml similarity index 66% rename from hawkbit-rest-api/pom.xml rename to hawkbit-mgmt-api/pom.xml index 703d6caf3..4c99cd7bc 100644 --- a/hawkbit-rest-api/pom.xml +++ b/hawkbit-mgmt-api/pom.xml @@ -16,15 +16,10 @@ hawkbit-parent 0.2.0-SNAPSHOT - hawkbit-rest-api - hawkBit :: REST API - + hawkbit-mgmt-api + hawkBit :: Mgmt REST API - - javax.validation - validation-api - org.springframework.hateoas spring-hateoas @@ -33,5 +28,26 @@ com.fasterxml.jackson.core jackson-annotations + + javax.validation + validation-api + + + javax.servlet + javax.servlet-api + provided + + + + + org.easytesting + fest-assert + test + + + ru.yandex.qatools.allure + allure-junit-adaptor + test + \ No newline at end of file diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/BaseEntityRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtBaseEntity.java similarity index 94% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/BaseEntityRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtBaseEntity.java index 6d80a407c..728734050 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/BaseEntityRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtBaseEntity.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model; +package org.eclipse.hawkbit.mgmt.json.model; import org.springframework.hateoas.ResourceSupport; @@ -17,7 +17,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * A json annotated rest model for BaseEntity to RESTful API representation. * */ -public abstract class BaseEntityRest extends ResourceSupport { +public abstract class MgmtBaseEntity extends ResourceSupport { @JsonProperty private String createdBy; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/IdRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtId.java similarity index 92% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/IdRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtId.java index d15114d4e..e83c43d52 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/IdRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtId.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model; +package org.eclipse.hawkbit.mgmt.json.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -18,7 +18,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * */ @JsonIgnoreProperties(ignoreUnknown = true) -public class IdRest { +public class MgmtId { @JsonProperty private Long id; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/MetadataRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtMetadata.java similarity index 94% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/MetadataRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtMetadata.java index a5c24c4a9..6a6371d6b 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/MetadataRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtMetadata.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model; +package org.eclipse.hawkbit.mgmt.json.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class MetadataRest { +public class MgmtMetadata { @JsonProperty(required = true) private String key; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/NamedEntityRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtNamedEntity.java similarity index 91% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/NamedEntityRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtNamedEntity.java index d82d14f75..d335261ad 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/NamedEntityRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtNamedEntity.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model; +package org.eclipse.hawkbit.mgmt.json.model; import com.fasterxml.jackson.annotation.JsonProperty; @@ -14,7 +14,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * A json annotated rest model for NamedEntity to RESTful API representation. * */ -public abstract class NamedEntityRest extends BaseEntityRest { +public abstract class MgmtNamedEntity extends MgmtBaseEntity { @JsonProperty(required = true) private String name; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/PollStatusRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtPollStatus.java similarity index 95% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/PollStatusRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtPollStatus.java index d66d02512..5e5163a6a 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/PollStatusRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/MgmtPollStatus.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model; +package org.eclipse.hawkbit.mgmt.json.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -22,7 +22,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class PollStatusRest { +public class MgmtPollStatus { @JsonProperty private Long lastRequestAt; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/PagedList.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/PagedList.java similarity index 97% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/PagedList.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/PagedList.java index 9d5cc458c..173f3ce31 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/PagedList.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/PagedList.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model; +package org.eclipse.hawkbit.mgmt.json.model; import java.util.List; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/action/ActionRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/action/MgmtAction.java similarity index 87% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/action/ActionRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/action/MgmtAction.java index 630bcb993..234e282a0 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/action/ActionRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/action/MgmtAction.java @@ -6,9 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.action; +package org.eclipse.hawkbit.mgmt.json.model.action; -import org.eclipse.hawkbit.rest.resource.model.BaseEntityRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtBaseEntity; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -21,15 +21,15 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class ActionRest extends BaseEntityRest { +public class MgmtAction extends MgmtBaseEntity { /** - * API definition for {@link UpdateAction}. + * API definition for update action}. */ public static final String ACTION_UPDATE = "update"; /** - * API definition for {@link CancelAction}. + * API definition for cancel action. */ public static final String ACTION_CANCEL = "cancel"; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/action/ActionStatusRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/action/MgmtActionStatus.java similarity index 97% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/action/ActionStatusRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/action/MgmtActionStatus.java index e5af39bac..26120d2d5 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/action/ActionStatusRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/action/MgmtActionStatus.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.action; +package org.eclipse.hawkbit.mgmt.json.model.action; import java.util.List; @@ -21,7 +21,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class ActionStatusRest { +public class MgmtActionStatus { /** * Action is finished successfully for this target. diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/artifact/ArtifactRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/artifact/MgmtArtifact.java similarity index 86% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/artifact/ArtifactRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/artifact/MgmtArtifact.java index f32a32ed8..afb2d204a 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/artifact/ArtifactRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/artifact/MgmtArtifact.java @@ -6,9 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.artifact; +package org.eclipse.hawkbit.mgmt.json.model.artifact; -import org.eclipse.hawkbit.rest.resource.model.BaseEntityRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtBaseEntity; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -22,7 +22,8 @@ import com.fasterxml.jackson.annotation.JsonValue; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class ArtifactRest extends BaseEntityRest { +public class MgmtArtifact extends MgmtBaseEntity { + @JsonProperty(required = true) private ArtifactType type; @@ -30,7 +31,7 @@ public class ArtifactRest extends BaseEntityRest { private Long artifactId; @JsonProperty - private ArtifactHash hashes; + private MgmtArtifactHash hashes; @JsonProperty private String providedFilename; @@ -38,6 +39,11 @@ public class ArtifactRest extends BaseEntityRest { @JsonProperty private Long size; + public MgmtArtifact() { + super(); + // need for json encoder + } + /** * @param type * the type to set @@ -51,7 +57,7 @@ public class ArtifactRest extends BaseEntityRest { * the hashes to set */ @JsonIgnore - public void setHashes(final ArtifactHash hashes) { + public void setHashes(final MgmtArtifactHash hashes) { this.hashes = hashes; } @@ -81,7 +87,7 @@ public class ArtifactRest extends BaseEntityRest { /** * @return the hashes */ - public ArtifactHash getHashes() { + public MgmtArtifactHash getHashes() { return hashes; } @@ -102,11 +108,7 @@ public class ArtifactRest extends BaseEntityRest { } /** - * Type maps to either {@link LocalArtifact} or {@link ExternalArtifact}. - * - * - * - * + * Type maps to either local artifact} or external artifact. */ public enum ArtifactType { LOCAL("local"), EXTERNAL("external"); diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/artifact/ArtifactHash.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/artifact/MgmtArtifactHash.java similarity index 83% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/artifact/ArtifactHash.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/artifact/MgmtArtifactHash.java index 58b81d8fd..d43ae4339 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/artifact/ArtifactHash.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/artifact/MgmtArtifactHash.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.artifact; +package org.eclipse.hawkbit.mgmt.json.model.artifact; import com.fasterxml.jackson.annotation.JsonProperty; @@ -15,7 +15,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * * */ -public class ArtifactHash { +public class MgmtArtifactHash { @JsonProperty private String sha1; @@ -26,7 +26,7 @@ public class ArtifactHash { /** * Default constructor. */ - public ArtifactHash() { + public MgmtArtifactHash() { } /** @@ -35,7 +35,7 @@ public class ArtifactHash { * @param sha1 * @param md5 */ - public ArtifactHash(final String sha1, final String md5) { + public MgmtArtifactHash(final String sha1, final String md5) { super(); this.sha1 = sha1; this.md5 = md5; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/ActionTypeRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtActionType.java similarity index 74% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/ActionTypeRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtActionType.java index bf6a649a0..d95375f5a 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/ActionTypeRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtActionType.java @@ -6,18 +6,15 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.distributionset; +package org.eclipse.hawkbit.mgmt.json.model.distributionset; import com.fasterxml.jackson.annotation.JsonValue; /** - * Definition of the {@link ActionType} for the REST management API. - * - * - * + * Definition of the Action type for the REST management API. * */ -public enum ActionTypeRest { +public enum MgmtActionType { /** * The soft action type. */ @@ -35,13 +32,10 @@ public enum ActionTypeRest { private final String name; - private ActionTypeRest(final String name) { + private MgmtActionType(final String name) { this.name = name; } - /** - * @return the name - */ @JsonValue public String getName() { return name; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/DistributionSetRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSet.java similarity index 86% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/DistributionSetRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSet.java index 2ff764eba..7caaf4cdd 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/DistributionSetRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSet.java @@ -6,13 +6,13 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.distributionset; +package org.eclipse.hawkbit.mgmt.json.model.distributionset; import java.util.ArrayList; import java.util.List; -import org.eclipse.hawkbit.rest.resource.model.NamedEntityRest; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -30,7 +30,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class DistributionSetRest extends NamedEntityRest { +public class MgmtDistributionSet extends MgmtNamedEntity { @JsonProperty(value = "id", required = true) private Long dsId; @@ -39,7 +39,7 @@ public class DistributionSetRest extends NamedEntityRest { private String version; @JsonProperty - private List modules = new ArrayList<>(); + private List modules = new ArrayList<>(); @JsonProperty private boolean requiredMigrationStep; @@ -99,7 +99,7 @@ public class DistributionSetRest extends NamedEntityRest { /** * @return the modules */ - public List getModules() { + public List getModules() { return modules; } @@ -107,7 +107,7 @@ public class DistributionSetRest extends NamedEntityRest { * @param modules * the modules to set */ - public void setModules(final List modules) { + public void setModules(final List modules) { this.modules = modules; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/DistributionSetRequestBodyPost.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetRequestBodyPost.java similarity index 67% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/DistributionSetRequestBodyPost.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetRequestBodyPost.java index bf5470d72..a56b5aaba 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/DistributionSetRequestBodyPost.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetRequestBodyPost.java @@ -6,11 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.distributionset; +package org.eclipse.hawkbit.mgmt.json.model.distributionset; import java.util.List; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleAssigmentRest; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleAssigment; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -23,22 +23,22 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class DistributionSetRequestBodyPost extends DistributionSetRequestBodyPut { +public class MgmtDistributionSetRequestBodyPost extends MgmtDistributionSetRequestBodyPut { // deprecated format from the time where os, application and runtime where // statically defined @JsonProperty - private SoftwareModuleAssigmentRest os; + private MgmtSoftwareModuleAssigment os; @JsonProperty - private SoftwareModuleAssigmentRest runtime; + private MgmtSoftwareModuleAssigment runtime; @JsonProperty - private SoftwareModuleAssigmentRest application; + private MgmtSoftwareModuleAssigment application; // deprecated format - END @JsonProperty - private List modules; + private List modules; @JsonProperty private boolean requiredMigrationStep; @@ -49,7 +49,7 @@ public class DistributionSetRequestBodyPost extends DistributionSetRequestBodyPu /** * @return the os */ - public SoftwareModuleAssigmentRest getOs() { + public MgmtSoftwareModuleAssigment getOs() { return os; } @@ -59,7 +59,7 @@ public class DistributionSetRequestBodyPost extends DistributionSetRequestBodyPu * * @return updated body */ - public DistributionSetRequestBodyPost setOs(final SoftwareModuleAssigmentRest os) { + public MgmtDistributionSetRequestBodyPost setOs(final MgmtSoftwareModuleAssigment os) { this.os = os; return this; } @@ -67,7 +67,7 @@ public class DistributionSetRequestBodyPost extends DistributionSetRequestBodyPu /** * @return the runtime */ - public SoftwareModuleAssigmentRest getRuntime() { + public MgmtSoftwareModuleAssigment getRuntime() { return runtime; } @@ -77,7 +77,7 @@ public class DistributionSetRequestBodyPost extends DistributionSetRequestBodyPu * * @return updated body */ - public DistributionSetRequestBodyPost setRuntime(final SoftwareModuleAssigmentRest runtime) { + public MgmtDistributionSetRequestBodyPost setRuntime(final MgmtSoftwareModuleAssigment runtime) { this.runtime = runtime; return this; @@ -86,7 +86,7 @@ public class DistributionSetRequestBodyPost extends DistributionSetRequestBodyPu /** * @return the application */ - public SoftwareModuleAssigmentRest getApplication() { + public MgmtSoftwareModuleAssigment getApplication() { return application; } @@ -96,7 +96,7 @@ public class DistributionSetRequestBodyPost extends DistributionSetRequestBodyPu * * @return updated body */ - public DistributionSetRequestBodyPost setApplication(final SoftwareModuleAssigmentRest application) { + public MgmtDistributionSetRequestBodyPost setApplication(final MgmtSoftwareModuleAssigment application) { this.application = application; return this; @@ -115,7 +115,7 @@ public class DistributionSetRequestBodyPost extends DistributionSetRequestBodyPu * * @return updated body */ - public DistributionSetRequestBodyPost setRequiredMigrationStep(final boolean requiredMigrationStep) { + public MgmtDistributionSetRequestBodyPost setRequiredMigrationStep(final boolean requiredMigrationStep) { this.requiredMigrationStep = requiredMigrationStep; return this; @@ -124,7 +124,7 @@ public class DistributionSetRequestBodyPost extends DistributionSetRequestBodyPu /** * @return the modules */ - public List getModules() { + public List getModules() { return modules; } @@ -134,7 +134,7 @@ public class DistributionSetRequestBodyPost extends DistributionSetRequestBodyPu * * @return updated body */ - public DistributionSetRequestBodyPost setModules(final List modules) { + public MgmtDistributionSetRequestBodyPost setModules(final List modules) { this.modules = modules; return this; @@ -153,7 +153,7 @@ public class DistributionSetRequestBodyPost extends DistributionSetRequestBodyPu * * @return updated body */ - public DistributionSetRequestBodyPost setType(final String type) { + public MgmtDistributionSetRequestBodyPost setType(final String type) { this.type = type; return this; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/DistributionSetRequestBodyPut.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetRequestBodyPut.java similarity index 82% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/DistributionSetRequestBodyPut.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetRequestBodyPut.java index 2f19625f3..4494dd8a8 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/DistributionSetRequestBodyPut.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetRequestBodyPut.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.distributionset; +package org.eclipse.hawkbit.mgmt.json.model.distributionset; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class DistributionSetRequestBodyPut { +public class MgmtDistributionSetRequestBodyPut { @JsonProperty private String name; @@ -43,7 +43,7 @@ public class DistributionSetRequestBodyPut { * * @return updated body */ - public DistributionSetRequestBodyPut setName(final String name) { + public MgmtDistributionSetRequestBodyPut setName(final String name) { this.name = name; return this; } @@ -61,7 +61,7 @@ public class DistributionSetRequestBodyPut { * * @return updated body */ - public DistributionSetRequestBodyPut setDescription(final String description) { + public MgmtDistributionSetRequestBodyPut setDescription(final String description) { this.description = description; return this; @@ -80,7 +80,7 @@ public class DistributionSetRequestBodyPut { * * @return updated body */ - public DistributionSetRequestBodyPut setVersion(final String version) { + public MgmtDistributionSetRequestBodyPut setVersion(final String version) { this.version = version; return this; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/TargetAssignmentRequestBody.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtTargetAssignmentRequestBody.java similarity index 85% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/TargetAssignmentRequestBody.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtTargetAssignmentRequestBody.java index 5135a977c..46c43ac8b 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/TargetAssignmentRequestBody.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtTargetAssignmentRequestBody.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.distributionset; +package org.eclipse.hawkbit.mgmt.json.model.distributionset; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -16,14 +16,14 @@ import com.fasterxml.jackson.annotation.JsonProperty; * */ @JsonIgnoreProperties(ignoreUnknown = true) -public class TargetAssignmentRequestBody { +public class MgmtTargetAssignmentRequestBody { @JsonProperty private String id; private long forcetime; - private ActionTypeRest type; + private MgmtActionType type; /** * @return the id @@ -43,7 +43,7 @@ public class TargetAssignmentRequestBody { /** * @return the type */ - public ActionTypeRest getType() { + public MgmtActionType getType() { return type; } @@ -51,7 +51,7 @@ public class TargetAssignmentRequestBody { * @param type * the type to set */ - public void setType(final ActionTypeRest type) { + public void setType(final MgmtActionType type) { this.type = type; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/TargetAssignmentResponseBody.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtTargetAssignmentResponseBody.java similarity index 93% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/TargetAssignmentResponseBody.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtTargetAssignmentResponseBody.java index 77676f844..d5247c577 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionset/TargetAssignmentResponseBody.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtTargetAssignmentResponseBody.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.distributionset; +package org.eclipse.hawkbit.mgmt.json.model.distributionset; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class TargetAssignmentResponseBody { +public class MgmtTargetAssignmentResponseBody { private int assigned; private int alreadyAssigned; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionsettype/DistributionSetTypeRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionsettype/MgmtDistributionSetType.java similarity index 87% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionsettype/DistributionSetTypeRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionsettype/MgmtDistributionSetType.java index e282b2924..acc4dbb59 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionsettype/DistributionSetTypeRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionsettype/MgmtDistributionSetType.java @@ -6,9 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.distributionsettype; +package org.eclipse.hawkbit.mgmt.json.model.distributionsettype; -import org.eclipse.hawkbit.rest.resource.model.NamedEntityRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -25,7 +25,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class DistributionSetTypeRest extends NamedEntityRest { +public class MgmtDistributionSetType extends MgmtNamedEntity { @JsonProperty(value = "id", required = true) private Long moduleId; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionsettype/DistributionSetTypeRequestBodyPost.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionsettype/MgmtDistributionSetTypeRequestBodyPost.java similarity index 68% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionsettype/DistributionSetTypeRequestBodyPost.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionsettype/MgmtDistributionSetTypeRequestBodyPost.java index ba0f548f6..82ecb2cc5 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionsettype/DistributionSetTypeRequestBodyPost.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionsettype/MgmtDistributionSetTypeRequestBodyPost.java @@ -6,11 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.distributionsettype; +package org.eclipse.hawkbit.mgmt.json.model.distributionsettype; import java.util.List; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeAssigmentRest; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeAssigment; import com.fasterxml.jackson.annotation.JsonProperty; @@ -18,7 +18,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * Request Body for DistributionSetType POST. * */ -public class DistributionSetTypeRequestBodyPost { +public class MgmtDistributionSetTypeRequestBodyPost { @JsonProperty(required = true) private String name; @@ -30,10 +30,10 @@ public class DistributionSetTypeRequestBodyPost { private String key; @JsonProperty - private List mandatorymodules; + private List mandatorymodules; @JsonProperty - private List optionalmodules; + private List optionalmodules; /** * @return the name @@ -48,7 +48,7 @@ public class DistributionSetTypeRequestBodyPost { * * @return updated body */ - public DistributionSetTypeRequestBodyPost setName(final String name) { + public MgmtDistributionSetTypeRequestBodyPost setName(final String name) { this.name = name; return this; } @@ -66,7 +66,7 @@ public class DistributionSetTypeRequestBodyPost { * * @return updated body */ - public DistributionSetTypeRequestBodyPost setDescription(final String description) { + public MgmtDistributionSetTypeRequestBodyPost setDescription(final String description) { this.description = description; return this; } @@ -84,7 +84,7 @@ public class DistributionSetTypeRequestBodyPost { * * @return updated body */ - public DistributionSetTypeRequestBodyPost setKey(final String key) { + public MgmtDistributionSetTypeRequestBodyPost setKey(final String key) { this.key = key; return this; } @@ -92,7 +92,7 @@ public class DistributionSetTypeRequestBodyPost { /** * @return the mandatory modules */ - public List getMandatorymodules() { + public List getMandatorymodules() { return mandatorymodules; } @@ -102,8 +102,8 @@ public class DistributionSetTypeRequestBodyPost { * * @return updated body */ - public DistributionSetTypeRequestBodyPost setMandatorymodules( - final List mandatorymodules) { + public MgmtDistributionSetTypeRequestBodyPost setMandatorymodules( + final List mandatorymodules) { this.mandatorymodules = mandatorymodules; return this; } @@ -111,7 +111,7 @@ public class DistributionSetTypeRequestBodyPost { /** * @return the optional modules */ - public List getOptionalmodules() { + public List getOptionalmodules() { return optionalmodules; } @@ -121,8 +121,8 @@ public class DistributionSetTypeRequestBodyPost { * * @return updated body */ - public DistributionSetTypeRequestBodyPost setOptionalmodules( - final List optionalmodules) { + public MgmtDistributionSetTypeRequestBodyPost setOptionalmodules( + final List optionalmodules) { this.optionalmodules = optionalmodules; return this; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionsettype/DistributionSetTypeRequestBodyPut.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionsettype/MgmtDistributionSetTypeRequestBodyPut.java similarity index 79% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionsettype/DistributionSetTypeRequestBodyPut.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionsettype/MgmtDistributionSetTypeRequestBodyPut.java index 6bf21b93f..220f58e4d 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/distributionsettype/DistributionSetTypeRequestBodyPut.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionsettype/MgmtDistributionSetTypeRequestBodyPut.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.distributionsettype; +package org.eclipse.hawkbit.mgmt.json.model.distributionsettype; import com.fasterxml.jackson.annotation.JsonProperty; @@ -14,7 +14,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * Request Body for DistributionSetType PUT, i.e. update. * */ -public class DistributionSetTypeRequestBodyPut { +public class MgmtDistributionSetTypeRequestBodyPut { @JsonProperty private String description; @@ -32,7 +32,7 @@ public class DistributionSetTypeRequestBodyPut { * * @return updated body */ - public DistributionSetTypeRequestBodyPut setDescription(final String description) { + public MgmtDistributionSetTypeRequestBodyPut setDescription(final String description) { this.description = description; return this; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutCondition.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutCondition.java similarity index 84% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutCondition.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutCondition.java index 914a5d5c2..d83585415 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutCondition.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutCondition.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.rollout; +package org.eclipse.hawkbit.mgmt.json.model.rollout; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -17,7 +17,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class RolloutCondition { +public class MgmtRolloutCondition { private Condition condition = Condition.THRESHOLD; private String expression = "100"; @@ -25,10 +25,11 @@ public class RolloutCondition { /** * */ - public RolloutCondition() { + public MgmtRolloutCondition() { + // needed for jackson json creator. } - public RolloutCondition(final Condition condition, final String expression) { + public MgmtRolloutCondition(final Condition condition, final String expression) { this.condition = condition; this.expression = expression; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutErrorAction.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutErrorAction.java similarity index 93% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutErrorAction.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutErrorAction.java index 2ed6077e6..71fdf3ac9 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutErrorAction.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutErrorAction.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.rollout; +package org.eclipse.hawkbit.mgmt.json.model.rollout; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -17,7 +17,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class RolloutErrorAction { +public class MgmtRolloutErrorAction { private ErrorAction action = ErrorAction.PAUSE; private String expression = null; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutResponseBody.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutResponseBody.java similarity index 94% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutResponseBody.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutResponseBody.java index dd1296cfd..79455f501 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutResponseBody.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutResponseBody.java @@ -6,12 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.rollout; +package org.eclipse.hawkbit.mgmt.json.model.rollout; import java.util.HashMap; import java.util.Map; -import org.eclipse.hawkbit.rest.resource.model.NamedEntityRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -23,7 +23,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class RolloutResponseBody extends NamedEntityRest { +public class MgmtRolloutResponseBody extends MgmtNamedEntity { private String targetFilterQuery; private Long distributionSetId; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutRestRequestBody.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutRestRequestBody.java similarity index 72% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutRestRequestBody.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutRestRequestBody.java index 0b83948ff..f3bdb2665 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutRestRequestBody.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutRestRequestBody.java @@ -6,10 +6,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.rollout; +package org.eclipse.hawkbit.mgmt.json.model.rollout; -import org.eclipse.hawkbit.rest.resource.model.NamedEntityRest; -import org.eclipse.hawkbit.rest.resource.model.distributionset.ActionTypeRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -21,26 +21,26 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class RolloutRestRequestBody extends NamedEntityRest { +public class MgmtRolloutRestRequestBody extends MgmtNamedEntity { private String targetFilterQuery; private long distributionSetId; private int amountGroups = 1; - private RolloutCondition successCondition = new RolloutCondition(); - private RolloutSuccessAction successAction = new RolloutSuccessAction(); - private RolloutCondition errorCondition = null; - private RolloutErrorAction errorAction = null; + private MgmtRolloutCondition successCondition = new MgmtRolloutCondition(); + private MgmtRolloutSuccessAction successAction = new MgmtRolloutSuccessAction(); + private MgmtRolloutCondition errorCondition = null; + private MgmtRolloutErrorAction errorAction = null; private Long forcetime; - private ActionTypeRest type; + private MgmtActionType type; /** * @return the finishCondition */ - public RolloutCondition getSuccessCondition() { + public MgmtRolloutCondition getSuccessCondition() { return successCondition; } @@ -48,14 +48,14 @@ public class RolloutRestRequestBody extends NamedEntityRest { * @param successCondition * the finishCondition to set */ - public void setSuccessCondition(final RolloutCondition successCondition) { + public void setSuccessCondition(final MgmtRolloutCondition successCondition) { this.successCondition = successCondition; } /** * @return the successAction */ - public RolloutSuccessAction getSuccessAction() { + public MgmtRolloutSuccessAction getSuccessAction() { return successAction; } @@ -63,14 +63,14 @@ public class RolloutRestRequestBody extends NamedEntityRest { * @param successAction * the successAction to set */ - public void setSuccessAction(final RolloutSuccessAction successAction) { + public void setSuccessAction(final MgmtRolloutSuccessAction successAction) { this.successAction = successAction; } /** * @return the errorCondition */ - public RolloutCondition getErrorCondition() { + public MgmtRolloutCondition getErrorCondition() { return errorCondition; } @@ -78,7 +78,7 @@ public class RolloutRestRequestBody extends NamedEntityRest { * @param errorCondition * the errorCondition to set */ - public void setErrorCondition(final RolloutCondition errorCondition) { + public void setErrorCondition(final MgmtRolloutCondition errorCondition) { this.errorCondition = errorCondition; } @@ -145,7 +145,7 @@ public class RolloutRestRequestBody extends NamedEntityRest { /** * @return the type */ - public ActionTypeRest getType() { + public MgmtActionType getType() { return type; } @@ -153,14 +153,14 @@ public class RolloutRestRequestBody extends NamedEntityRest { * @param type * the type to set */ - public void setType(final ActionTypeRest type) { + public void setType(final MgmtActionType type) { this.type = type; } /** * @return the errorAction */ - public RolloutErrorAction getErrorAction() { + public MgmtRolloutErrorAction getErrorAction() { return errorAction; } @@ -168,7 +168,7 @@ public class RolloutRestRequestBody extends NamedEntityRest { * @param errorAction * the errorAction to set */ - public void setErrorAction(final RolloutErrorAction errorAction) { + public void setErrorAction(final MgmtRolloutErrorAction errorAction) { this.errorAction = errorAction; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutSuccessAction.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutSuccessAction.java similarity index 84% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutSuccessAction.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutSuccessAction.java index f14e9a8bf..174aa63fa 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rollout/RolloutSuccessAction.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rollout/MgmtRolloutSuccessAction.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.rollout; +package org.eclipse.hawkbit.mgmt.json.model.rollout; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -17,7 +17,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class RolloutSuccessAction { +public class MgmtRolloutSuccessAction { private SuccessAction action = SuccessAction.NEXTGROUP; private String expression = null; @@ -25,10 +25,11 @@ public class RolloutSuccessAction { /** * */ - public RolloutSuccessAction() { + public MgmtRolloutSuccessAction() { + // needed for json creator } - public RolloutSuccessAction(final SuccessAction action, final String expression) { + public MgmtRolloutSuccessAction(final SuccessAction action, final String expression) { this.action = action; this.expression = expression; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rolloutgroup/RolloutGroupResponseBody.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rolloutgroup/MgmtRolloutGroupResponseBody.java similarity index 88% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rolloutgroup/RolloutGroupResponseBody.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rolloutgroup/MgmtRolloutGroupResponseBody.java index bb1b0116e..5e740a1fb 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/rolloutgroup/RolloutGroupResponseBody.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/rolloutgroup/MgmtRolloutGroupResponseBody.java @@ -6,9 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.rolloutgroup; +package org.eclipse.hawkbit.mgmt.json.model.rolloutgroup; -import org.eclipse.hawkbit.rest.resource.model.NamedEntityRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -21,7 +21,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class RolloutGroupResponseBody extends NamedEntityRest { +public class MgmtRolloutGroupResponseBody extends MgmtNamedEntity { @JsonProperty(value = "id", required = true) private Long rolloutGroupId; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModule.java similarity index 78% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModule.java index a5ab41c8b..08b723198 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModule.java @@ -6,9 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.softwaremodule; +package org.eclipse.hawkbit.mgmt.json.model.softwaremodule; -import org.eclipse.hawkbit.rest.resource.model.NamedEntityRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -22,20 +22,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class SoftwareModuleRest extends NamedEntityRest { - /** - * API definition for {@link SoftwareModule.Type#RUNTIME}. - */ - public static final String SM_RUNTIME = "runtime"; - /** - * API definition for {@link SoftwareModule.Type#OS}. - */ - public static final String SM_OS = "os"; - /** - * API definition for {@link SoftwareModule.Type#APPLICATION}. - */ - public static final String SM_APPLICATION = "application"; - +public class MgmtSoftwareModule extends MgmtNamedEntity { @JsonProperty(value = "id", required = true) private Long moduleId; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleAssigmentRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleAssigment.java similarity index 73% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleAssigmentRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleAssigment.java index 3c866dca6..79bc31ad3 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleAssigmentRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleAssigment.java @@ -6,20 +6,17 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.softwaremodule; +package org.eclipse.hawkbit.mgmt.json.model.softwaremodule; -import org.eclipse.hawkbit.rest.resource.model.IdRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtId; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; /** * Request Body of SoftwareModule for assignment operations (ID only). * - * - * - * */ @JsonIgnoreProperties(ignoreUnknown = true) -public class SoftwareModuleAssigmentRest extends IdRest { +public class MgmtSoftwareModuleAssigment extends MgmtId { } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleRequestBodyPost.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleRequestBodyPost.java similarity index 80% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleRequestBodyPost.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleRequestBodyPost.java index 08638c10f..e39413915 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleRequestBodyPost.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleRequestBodyPost.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.softwaremodule; +package org.eclipse.hawkbit.mgmt.json.model.softwaremodule; import com.fasterxml.jackson.annotation.JsonProperty; @@ -14,7 +14,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * Request Body for SoftwareModule POST. * */ -public class SoftwareModuleRequestBodyPost { +public class MgmtSoftwareModuleRequestBodyPost { @JsonProperty(required = true) private String name; @@ -44,7 +44,7 @@ public class SoftwareModuleRequestBodyPost { * * @return updated body */ - public SoftwareModuleRequestBodyPost setName(final String name) { + public MgmtSoftwareModuleRequestBodyPost setName(final String name) { this.name = name; return this; } @@ -62,7 +62,7 @@ public class SoftwareModuleRequestBodyPost { * * @return updated body */ - public SoftwareModuleRequestBodyPost setVersion(final String version) { + public MgmtSoftwareModuleRequestBodyPost setVersion(final String version) { this.version = version; return this; } @@ -80,7 +80,7 @@ public class SoftwareModuleRequestBodyPost { * * @return updated body */ - public SoftwareModuleRequestBodyPost setType(final String type) { + public MgmtSoftwareModuleRequestBodyPost setType(final String type) { this.type = type; return this; } @@ -98,7 +98,7 @@ public class SoftwareModuleRequestBodyPost { * * @return updated body */ - public SoftwareModuleRequestBodyPost setDescription(final String description) { + public MgmtSoftwareModuleRequestBodyPost setDescription(final String description) { this.description = description; return this; } @@ -116,7 +116,7 @@ public class SoftwareModuleRequestBodyPost { * * @return updated body */ - public SoftwareModuleRequestBodyPost setVendor(final String vendor) { + public MgmtSoftwareModuleRequestBodyPost setVendor(final String vendor) { this.vendor = vendor; return this; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleRequestBodyPut.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleRequestBodyPut.java similarity index 80% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleRequestBodyPut.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleRequestBodyPut.java index 1ee547886..52c097e39 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremodule/SoftwareModuleRequestBodyPut.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleRequestBodyPut.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.softwaremodule; +package org.eclipse.hawkbit.mgmt.json.model.softwaremodule; import com.fasterxml.jackson.annotation.JsonProperty; @@ -14,7 +14,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * Request Body for SoftwareModule PUT. * */ -public class SoftwareModuleRequestBodyPut { +public class MgmtSoftwareModuleRequestBodyPut { @JsonProperty private String description; @@ -35,7 +35,7 @@ public class SoftwareModuleRequestBodyPut { * * @return updated body */ - public SoftwareModuleRequestBodyPut setDescription(final String description) { + public MgmtSoftwareModuleRequestBodyPut setDescription(final String description) { this.description = description; return this; } @@ -53,7 +53,7 @@ public class SoftwareModuleRequestBodyPut { * * @return updated body */ - public SoftwareModuleRequestBodyPut setVendor(final String vendor) { + public MgmtSoftwareModuleRequestBodyPut setVendor(final String vendor) { this.vendor = vendor; return this; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleType.java similarity index 90% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleType.java index ed05c1ee4..c0cda4994 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleType.java @@ -6,9 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.softwaremoduletype; +package org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype; -import org.eclipse.hawkbit.rest.resource.model.NamedEntityRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -22,7 +22,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class SoftwareModuleTypeRest extends NamedEntityRest { +public class MgmtSoftwareModuleType extends MgmtNamedEntity { @JsonProperty(value = "id", required = true) private Long moduleId; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeAssigmentRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleTypeAssigment.java similarity index 73% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeAssigmentRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleTypeAssigment.java index 68709650b..43bdc157e 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeAssigmentRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleTypeAssigment.java @@ -6,9 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.softwaremoduletype; +package org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype; -import org.eclipse.hawkbit.rest.resource.model.IdRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtId; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -17,6 +17,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; * */ @JsonIgnoreProperties(ignoreUnknown = true) -public class SoftwareModuleTypeAssigmentRest extends IdRest { +public class MgmtSoftwareModuleTypeAssigment extends MgmtId { } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeRequestBodyPost.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleTypeRequestBodyPost.java similarity index 79% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeRequestBodyPost.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleTypeRequestBodyPost.java index 3528f6b98..836c39d19 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeRequestBodyPost.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleTypeRequestBodyPost.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.softwaremoduletype; +package org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype; import com.fasterxml.jackson.annotation.JsonProperty; @@ -14,7 +14,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * Request Body for SoftwareModuleType POST. * */ -public class SoftwareModuleTypeRequestBodyPost { +public class MgmtSoftwareModuleTypeRequestBodyPost { @JsonProperty(required = true) private String name; @@ -41,7 +41,7 @@ public class SoftwareModuleTypeRequestBodyPost { * * @return updated body */ - public SoftwareModuleTypeRequestBodyPost setName(final String name) { + public MgmtSoftwareModuleTypeRequestBodyPost setName(final String name) { this.name = name; return this; } @@ -59,7 +59,7 @@ public class SoftwareModuleTypeRequestBodyPost { * * @return updated body */ - public SoftwareModuleTypeRequestBodyPost setDescription(final String description) { + public MgmtSoftwareModuleTypeRequestBodyPost setDescription(final String description) { this.description = description; return this; } @@ -76,7 +76,7 @@ public class SoftwareModuleTypeRequestBodyPost { * the key to set * @return updated body */ - public SoftwareModuleTypeRequestBodyPost setKey(final String key) { + public MgmtSoftwareModuleTypeRequestBodyPost setKey(final String key) { this.key = key; return this; } @@ -94,7 +94,7 @@ public class SoftwareModuleTypeRequestBodyPost { * * @return updated body */ - public SoftwareModuleTypeRequestBodyPost setMaxAssignments(final int maxAssignments) { + public MgmtSoftwareModuleTypeRequestBodyPost setMaxAssignments(final int maxAssignments) { this.maxAssignments = maxAssignments; return this; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeRequestBodyPut.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleTypeRequestBodyPut.java similarity index 79% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeRequestBodyPut.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleTypeRequestBodyPut.java index 107a3cd2b..ecc8c9f65 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/softwaremoduletype/SoftwareModuleTypeRequestBodyPut.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremoduletype/MgmtSoftwareModuleTypeRequestBodyPut.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.softwaremoduletype; +package org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype; import com.fasterxml.jackson.annotation.JsonProperty; @@ -14,7 +14,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * Request Body for SoftwareModuleType PUT. * */ -public class SoftwareModuleTypeRequestBodyPut { +public class MgmtSoftwareModuleTypeRequestBodyPut { @JsonProperty private String description; @@ -32,7 +32,7 @@ public class SoftwareModuleTypeRequestBodyPut { * * @return updated body */ - public SoftwareModuleTypeRequestBodyPut setDescription(final String description) { + public MgmtSoftwareModuleTypeRequestBodyPut setDescription(final String description) { this.description = description; return this; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/system/TenantConfigurationValueRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/system/MgmtSystemTenantConfigurationValue.java similarity index 94% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/system/TenantConfigurationValueRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/system/MgmtSystemTenantConfigurationValue.java index 47dcfebe0..776b69c09 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/system/TenantConfigurationValueRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/system/MgmtSystemTenantConfigurationValue.java @@ -7,7 +7,7 @@ * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.system; +package org.eclipse.hawkbit.mgmt.json.model.system; import org.springframework.hateoas.ResourceSupport; @@ -22,7 +22,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class TenantConfigurationValueRest extends ResourceSupport { +public class MgmtSystemTenantConfigurationValue extends ResourceSupport { @JsonInclude(Include.ALWAYS) private Object value; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/system/TenantConfigurationValueRequest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/system/MgmtSystemTenantConfigurationValueRequest.java similarity index 80% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/system/TenantConfigurationValueRequest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/system/MgmtSystemTenantConfigurationValueRequest.java index b0ae6e546..9a9aed209 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/system/TenantConfigurationValueRequest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/system/MgmtSystemTenantConfigurationValueRequest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.system; +package org.eclipse.hawkbit.mgmt.json.model.system; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -18,21 +18,21 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class TenantConfigurationValueRequest { +public class MgmtSystemTenantConfigurationValueRequest { @JsonProperty(required = true) private Object value; /** * - * @return the value of the TenantConfigurationValueRequest + * @return the value of the MgmtSystemTenantConfigurationValueRequest */ public Object getValue() { return value; } /** - * Sets the TenantConfigurationValueRequest + * Sets the MgmtSystemTenantConfigurationValueRequest * * @param value */ diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/systemmanagement/CacheRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/systemmanagement/MgmtSystemCache.java similarity index 83% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/systemmanagement/CacheRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/systemmanagement/MgmtSystemCache.java index 35d35c0b1..2876b11df 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/systemmanagement/CacheRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/systemmanagement/MgmtSystemCache.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.systemmanagement; +package org.eclipse.hawkbit.mgmt.json.model.systemmanagement; import java.util.Collection; @@ -16,14 +16,11 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; /** * Model representation of an Cache entry as json. - * - * - * * */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class CacheRest { +public class MgmtSystemCache { private final String name; private final Collection keys; @@ -34,7 +31,7 @@ public class CacheRest { * @param cacheKeys * the keys which contains in the cache */ - public CacheRest(final String name, final Collection cacheKeys) { + public MgmtSystemCache(final String name, final Collection cacheKeys) { this.name = name; this.keys = cacheKeys; } @@ -60,6 +57,6 @@ public class CacheRest { */ @Override public String toString() { - return "CacheRest [name=" + name + ", keys=" + keys + "]"; + return "MgmtSystemCache [name=" + name + ", keys=" + keys + "]"; } } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/systemmanagement/SystemStatisticsRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/systemmanagement/MgmtSystemStatisticsRest.java similarity index 69% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/systemmanagement/SystemStatisticsRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/systemmanagement/MgmtSystemStatisticsRest.java index c69201d69..0c1b12fde 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/systemmanagement/SystemStatisticsRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/systemmanagement/MgmtSystemStatisticsRest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.systemmanagement; +package org.eclipse.hawkbit.mgmt.json.model.systemmanagement; import java.util.List; @@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class SystemStatisticsRest { +public class MgmtSystemStatisticsRest { private long overallTargets; private long overallArtifacts; @@ -28,13 +28,13 @@ public class SystemStatisticsRest { private long overallActions; private long overallTenants; - private List tenantStats; + private List tenantStats; public long getOverallTargets() { return overallTargets; } - public SystemStatisticsRest setOverallTargets(final long overallTargets) { + public MgmtSystemStatisticsRest setOverallTargets(final long overallTargets) { this.overallTargets = overallTargets; return this; } @@ -43,7 +43,7 @@ public class SystemStatisticsRest { return overallArtifacts; } - public SystemStatisticsRest setOverallArtifacts(final long overallArtifacts) { + public MgmtSystemStatisticsRest setOverallArtifacts(final long overallArtifacts) { this.overallArtifacts = overallArtifacts; return this; } @@ -52,7 +52,7 @@ public class SystemStatisticsRest { return overallArtifactVolumeInBytes; } - public SystemStatisticsRest setOverallArtifactVolumeInBytes(final long overallArtifactVolumeInBytes) { + public MgmtSystemStatisticsRest setOverallArtifactVolumeInBytes(final long overallArtifactVolumeInBytes) { this.overallArtifactVolumeInBytes = overallArtifactVolumeInBytes; return this; } @@ -61,7 +61,7 @@ public class SystemStatisticsRest { return overallActions; } - public SystemStatisticsRest setOverallActions(final long overallActions) { + public MgmtSystemStatisticsRest setOverallActions(final long overallActions) { this.overallActions = overallActions; return this; } @@ -70,16 +70,16 @@ public class SystemStatisticsRest { return overallTenants; } - public SystemStatisticsRest setOverallTenants(final long overallTenants) { + public MgmtSystemStatisticsRest setOverallTenants(final long overallTenants) { this.overallTenants = overallTenants; return this; } - public void setTenantStats(final List tenantStats) { + public void setTenantStats(final List tenantStats) { this.tenantStats = tenantStats; } - public List getTenantStats() { + public List getTenantStats() { return tenantStats; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/systemmanagement/TenantSystemUsageRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/systemmanagement/MgmtSystemTenantServiceUsage.java similarity index 90% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/systemmanagement/TenantSystemUsageRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/systemmanagement/MgmtSystemTenantServiceUsage.java index bc8653b36..c3e37421d 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/systemmanagement/TenantSystemUsageRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/systemmanagement/MgmtSystemTenantServiceUsage.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.systemmanagement; +package org.eclipse.hawkbit.mgmt.json.model.systemmanagement; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -18,7 +18,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class TenantSystemUsageRest { +public class MgmtSystemTenantServiceUsage { private final String tenantName; private long targets; @@ -31,8 +31,7 @@ public class TenantSystemUsageRest { * * @param tenantName */ - public TenantSystemUsageRest(final String tenantName) { - super(); + public MgmtSystemTenantServiceUsage(final String tenantName) { this.tenantName = tenantName; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/AssignedDistributionSetRequestBody.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtAssignedDistributionSetRequestBody.java similarity index 81% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/AssignedDistributionSetRequestBody.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtAssignedDistributionSetRequestBody.java index 2bfd6cbf8..469780abf 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/AssignedDistributionSetRequestBody.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtAssignedDistributionSetRequestBody.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.tag; +package org.eclipse.hawkbit.mgmt.json.model.tag; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class AssignedDistributionSetRequestBody { +public class MgmtAssignedDistributionSetRequestBody { @JsonProperty(value = "id", required = true) private Long distributionSetId; @@ -28,7 +28,7 @@ public class AssignedDistributionSetRequestBody { return distributionSetId; } - public AssignedDistributionSetRequestBody setDistributionSetId(final Long distributionSetId) { + public MgmtAssignedDistributionSetRequestBody setDistributionSetId(final Long distributionSetId) { this.distributionSetId = distributionSetId; return this; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/AssignedTargetRequestBody.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtAssignedTargetRequestBody.java similarity index 83% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/AssignedTargetRequestBody.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtAssignedTargetRequestBody.java index 2147c2697..6df1d10d7 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/AssignedTargetRequestBody.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtAssignedTargetRequestBody.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.tag; +package org.eclipse.hawkbit.mgmt.json.model.tag; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class AssignedTargetRequestBody { +public class MgmtAssignedTargetRequestBody { @JsonProperty(required = true) private String controllerId; @@ -28,7 +28,7 @@ public class AssignedTargetRequestBody { return controllerId; } - public AssignedTargetRequestBody setControllerId(final String controllerId) { + public MgmtAssignedTargetRequestBody setControllerId(final String controllerId) { this.controllerId = controllerId; return this; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/DistributionSetTagAssigmentResultRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtDistributionSetTagAssigmentResult.java similarity index 61% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/DistributionSetTagAssigmentResultRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtDistributionSetTagAssigmentResult.java index 2078fe891..892bac453 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/DistributionSetTagAssigmentResultRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtDistributionSetTagAssigmentResult.java @@ -6,11 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.tag; +package org.eclipse.hawkbit.mgmt.json.model.tag; import java.util.List; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -24,27 +24,27 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class DistributionSetTagAssigmentResultRest { +public class MgmtDistributionSetTagAssigmentResult { @JsonProperty - private List assignedDistributionSets; + private List assignedDistributionSets; @JsonProperty - private List unassignedDistributionSets; + private List unassignedDistributionSets; - public List getAssignedDistributionSets() { + public List getAssignedDistributionSets() { return assignedDistributionSets; } - public List getUnassignedDistributionSets() { + public List getUnassignedDistributionSets() { return unassignedDistributionSets; } - public void setAssignedDistributionSets(final List assignedDistributionSets) { + public void setAssignedDistributionSets(final List assignedDistributionSets) { this.assignedDistributionSets = assignedDistributionSets; } - public void setUnassignedDistributionSets(final List unassignedDistributionSets) { + public void setUnassignedDistributionSets(final List unassignedDistributionSets) { this.unassignedDistributionSets = unassignedDistributionSets; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/TagRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtTag.java similarity index 87% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/TagRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtTag.java index 54d3c5064..82c33b434 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/TagRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtTag.java @@ -6,9 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.tag; +package org.eclipse.hawkbit.mgmt.json.model.tag; -import org.eclipse.hawkbit.rest.resource.model.NamedEntityRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -22,7 +22,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class TagRest extends NamedEntityRest { +public class MgmtTag extends MgmtNamedEntity { @JsonProperty(value = "id", required = true) private Long tagId; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/TagRequestBodyPut.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtTagRequestBodyPut.java similarity index 80% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/TagRequestBodyPut.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtTagRequestBodyPut.java index 2165bcfc0..e7037af2b 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/TagRequestBodyPut.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtTagRequestBodyPut.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.tag; +package org.eclipse.hawkbit.mgmt.json.model.tag; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class TagRequestBodyPut { +public class MgmtTagRequestBodyPut { @JsonProperty private String colour; @@ -34,7 +34,7 @@ public class TagRequestBodyPut { return name; } - public TagRequestBodyPut setName(final String name) { + public MgmtTagRequestBodyPut setName(final String name) { this.name = name; return this; } @@ -43,12 +43,12 @@ public class TagRequestBodyPut { return description; } - public TagRequestBodyPut setDescription(final String description) { + public MgmtTagRequestBodyPut setDescription(final String description) { this.description = description; return this; } - public TagRequestBodyPut setColour(final String colour) { + public MgmtTagRequestBodyPut setColour(final String colour) { this.colour = colour; return this; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/TargetTagAssigmentResultRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtTargetTagAssigmentResult.java similarity index 67% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/TargetTagAssigmentResultRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtTargetTagAssigmentResult.java index 30d47cc90..61625e59d 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/tag/TargetTagAssigmentResultRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/tag/MgmtTargetTagAssigmentResult.java @@ -6,11 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model.tag; +package org.eclipse.hawkbit.mgmt.json.model.tag; import java.util.List; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -24,27 +24,27 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class TargetTagAssigmentResultRest { +public class MgmtTargetTagAssigmentResult { @JsonProperty - private List assignedTargets; + private List assignedTargets; @JsonProperty - private List unassignedTargets; + private List unassignedTargets; - public void setAssignedTargets(final List assignedTargets) { + public void setAssignedTargets(final List assignedTargets) { this.assignedTargets = assignedTargets; } - public List getAssignedTargets() { + public List getAssignedTargets() { return assignedTargets; } - public void setUnassignedTargets(final List unassignedTargets) { + public void setUnassignedTargets(final List unassignedTargets) { this.unassignedTargets = unassignedTargets; } - public List getUnassignedTargets() { + public List getUnassignedTargets() { return unassignedTargets; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/DistributionSetAssigmentRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtDistributionSetAssigment.java similarity index 64% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/DistributionSetAssigmentRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtDistributionSetAssigment.java index c2dc7f4a9..edfcc5687 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/DistributionSetAssigmentRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtDistributionSetAssigment.java @@ -1,23 +1,23 @@ /** * Copyright (c) 2011-2015 Bosch Software Innovations GmbH, Germany. All rights reserved. */ -package org.eclipse.hawkbit.rest.resource.model.target; +package org.eclipse.hawkbit.mgmt.json.model.target; -import org.eclipse.hawkbit.rest.resource.model.IdRest; -import org.eclipse.hawkbit.rest.resource.model.distributionset.ActionTypeRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtId; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType; /** * Request Body of DistributionSet for assignment operations (ID only). * */ -public class DistributionSetAssigmentRest extends IdRest { +public class MgmtDistributionSetAssigment extends MgmtId { private long forcetime; - private ActionTypeRest type; + private MgmtActionType type; /** * @return the type */ - public ActionTypeRest getType() { + public MgmtActionType getType() { return type; } @@ -25,7 +25,7 @@ public class DistributionSetAssigmentRest extends IdRest { * @param type * the type to set */ - public void setType(final ActionTypeRest type) { + public void setType(final MgmtActionType type) { this.type = type; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/TargetRest.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtTarget.java similarity index 90% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/TargetRest.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtTarget.java index 37baeeec9..40dd553a5 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/TargetRest.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtTarget.java @@ -1,12 +1,12 @@ /** * Copyright (c) 2011-2015 Bosch Software Innovations GmbH, Germany. All rights reserved. */ -package org.eclipse.hawkbit.rest.resource.model.target; +package org.eclipse.hawkbit.mgmt.json.model.target; import java.net.URI; -import org.eclipse.hawkbit.rest.resource.model.NamedEntityRest; -import org.eclipse.hawkbit.rest.resource.model.PollStatusRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity; +import org.eclipse.hawkbit.mgmt.json.model.MgmtPollStatus; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class TargetRest extends NamedEntityRest { +public class MgmtTarget extends MgmtNamedEntity { @JsonProperty(required = true) private String controllerId; @@ -41,7 +41,7 @@ public class TargetRest extends NamedEntityRest { private String address; @JsonProperty - private PollStatusRest pollStatus; + private MgmtPollStatus pollStatus; @JsonProperty private String securityToken; @@ -111,7 +111,7 @@ public class TargetRest extends NamedEntityRest { /** * @return the pollStatus */ - public PollStatusRest getPollStatus() { + public MgmtPollStatus getPollStatus() { return pollStatus; } @@ -120,7 +120,7 @@ public class TargetRest extends NamedEntityRest { * the pollStatus to set */ @JsonIgnore - public void setPollStatus(final PollStatusRest pollStatus) { + public void setPollStatus(final MgmtPollStatus pollStatus) { this.pollStatus = pollStatus; } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/TargetAttributes.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtTargetAttributes.java similarity index 63% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/TargetAttributes.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtTargetAttributes.java index 821be6b45..dad8e868f 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/TargetAttributes.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtTargetAttributes.java @@ -1,7 +1,7 @@ /** * Copyright (c) 2011-2015 Bosch Software Innovations GmbH, Germany. All rights reserved. */ -package org.eclipse.hawkbit.rest.resource.model.target; +package org.eclipse.hawkbit.mgmt.json.model.target; import java.util.HashMap; import java.util.Map; @@ -10,6 +10,6 @@ import java.util.Map; * {@link Map} with attributes of SP Target. * */ -public class TargetAttributes extends HashMap { +public class MgmtTargetAttributes extends HashMap { } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/TargetRequestBody.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtTargetRequestBody.java similarity index 60% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/TargetRequestBody.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtTargetRequestBody.java index bc1ca8a63..f7a297be1 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/target/TargetRequestBody.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/target/MgmtTargetRequestBody.java @@ -1,7 +1,7 @@ /** * Copyright (c) 2011-2015 Bosch Software Innovations GmbH, Germany. All rights reserved. */ -package org.eclipse.hawkbit.rest.resource.model.target; +package org.eclipse.hawkbit.mgmt.json.model.target; import com.fasterxml.jackson.annotation.JsonProperty; @@ -9,7 +9,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * Request body for target PUT/POST commands. * */ -public class TargetRequestBody { +public class MgmtTargetRequestBody { @JsonProperty(required = true) private String name; @@ -18,6 +18,20 @@ public class TargetRequestBody { @JsonProperty(required = true) private String controllerId; + @JsonProperty + private String address; + + @JsonProperty + private String securityToken; + + public String getSecurityToken() { + return securityToken; + } + + public void setSecurityToken(final String securityToken) { + this.securityToken = securityToken; + } + /** * @return the name */ @@ -43,7 +57,7 @@ public class TargetRequestBody { * @param name * the name to set */ - public TargetRequestBody setName(final String name) { + public MgmtTargetRequestBody setName(final String name) { this.name = name; return this; } @@ -52,7 +66,7 @@ public class TargetRequestBody { * @param description * the description to set */ - public TargetRequestBody setDescription(final String description) { + public MgmtTargetRequestBody setDescription(final String description) { this.description = description; return this; } @@ -61,9 +75,17 @@ public class TargetRequestBody { * @param controllerId * the controllerId to set */ - public TargetRequestBody setControllerId(final String controllerId) { + public MgmtTargetRequestBody setControllerId(final String controllerId) { this.controllerId = controllerId; return this; } + public String getAddress() { + return address; + } + + public void setAddress(final String address) { + this.address = address; + } + } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetRestApi.java similarity index 68% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetRestApi.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetRestApi.java index 80caefc94..c61c9ecd3 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetRestApi.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetRestApi.java @@ -6,22 +6,20 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ - -package org.eclipse.hawkbit.rest.resource.api; +package org.eclipse.hawkbit.mgmt.rest.api; import java.util.List; -import org.eclipse.hawkbit.rest.resource.RestConstants; -import org.eclipse.hawkbit.rest.resource.model.MetadataRest; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest; -import org.eclipse.hawkbit.rest.resource.model.distributionset.TargetAssignmentRequestBody; -import org.eclipse.hawkbit.rest.resource.model.distributionset.TargetAssignmentResponseBody; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleAssigmentRest; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPut; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentRequestBody; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentResponseBody; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleAssigment; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -33,8 +31,8 @@ import org.springframework.web.bind.annotation.RequestParam; /** * REST Resource handling for DistributionSet CRUD operations. */ -@RequestMapping(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING) -public interface DistributionSetRestApi { +@RequestMapping(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING) +public interface MgmtDistributionSetRestApi { /** * Handles the GET request of retrieving all DistributionSets . @@ -56,11 +54,11 @@ public interface DistributionSetRestApi { * JsonResponseExceptionHandler is handling the response. */ @RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getDistributionSets( - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + ResponseEntity> getDistributionSets( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the GET request of retrieving a single DistributionSet . @@ -70,12 +68,10 @@ public interface DistributionSetRestApi { * * @return a single DistributionSet with status OK. * - * @throws EntityNotFoundException - * in case no DistributionSet with the given ID exists. */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getDistributionSet( + ResponseEntity getDistributionSet( @PathVariable("distributionSetId") final Long distributionSetId); /** @@ -91,8 +87,8 @@ public interface DistributionSetRestApi { */ @RequestMapping(method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> createDistributionSets( - @RequestBody final List sets); + ResponseEntity> createDistributionSets( + @RequestBody final List sets); /** * Handles the DELETE request for a single DistributionSet . @@ -103,7 +99,7 @@ public interface DistributionSetRestApi { * */ @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetId}") - public ResponseEntity deleteDistributionSet(@PathVariable("distributionSetId") final Long distributionSetId); + ResponseEntity deleteDistributionSet(@PathVariable("distributionSetId") final Long distributionSetId); /** * Handles the UPDATE request for a single DistributionSet . @@ -118,9 +114,9 @@ public interface DistributionSetRestApi { */ @RequestMapping(method = RequestMethod.PUT, value = "/{distributionSetId}", consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity updateDistributionSet( + ResponseEntity updateDistributionSet( @PathVariable("distributionSetId") final Long distributionSetId, - @RequestBody final DistributionSetRequestBodyPut toUpdate); + @RequestBody final MgmtDistributionSetRequestBodyPut toUpdate); /** * Handles the GET request of retrieving assigned targets to a specific @@ -146,12 +142,12 @@ public interface DistributionSetRestApi { */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/assignedTargets", produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity> getAssignedTargets( + ResponseEntity> getAssignedTargets( @PathVariable("distributionSetId") final Long distributionSetId, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the GET request of retrieving installed targets to a specific @@ -177,12 +173,12 @@ public interface DistributionSetRestApi { */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/installedTargets", produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity> getInstalledTargets( + ResponseEntity> getInstalledTargets( @PathVariable("distributionSetId") final Long distributionSetId, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the POST request of assigning multiple targets to a single @@ -200,9 +196,9 @@ public interface DistributionSetRestApi { @RequestMapping(method = RequestMethod.POST, value = "/{distributionSetId}/assignedTargets", consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity createAssignedTarget( + ResponseEntity createAssignedTarget( @PathVariable("distributionSetId") final Long distributionSetId, - @RequestBody final List targetIds); + @RequestBody final List targetIds); /** * Gets a paged list of meta data for a distribution set. @@ -226,12 +222,11 @@ public interface DistributionSetRestApi { */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/metadata", produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity> getMetadata( - @PathVariable("distributionSetId") final Long distributionSetId, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + ResponseEntity> getMetadata(@PathVariable("distributionSetId") final Long distributionSetId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Gets a single meta data value for a specific key of a distribution set. @@ -245,8 +240,7 @@ public interface DistributionSetRestApi { */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/metadata/{metadataKey}", produces = { MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getMetadataValue( - @PathVariable("distributionSetId") final Long distributionSetId, + ResponseEntity getMetadataValue(@PathVariable("distributionSetId") final Long distributionSetId, @PathVariable("metadataKey") final String metadataKey); /** @@ -261,8 +255,8 @@ public interface DistributionSetRestApi { */ @RequestMapping(method = RequestMethod.PUT, value = "/{distributionSetId}/metadata/{metadataKey}", produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity updateMetadata(@PathVariable("distributionSetId") final Long distributionSetId, - @PathVariable("metadataKey") final String metadataKey, @RequestBody final MetadataRest metadata); + ResponseEntity updateMetadata(@PathVariable("distributionSetId") final Long distributionSetId, + @PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadata metadata); /** * Deletes a single meta data entry from the distribution set. @@ -274,7 +268,7 @@ public interface DistributionSetRestApi { * @return status OK if the delete request is successful */ @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetId}/metadata/{metadataKey}") - public ResponseEntity deleteMetadata(@PathVariable("distributionSetId") final Long distributionSetId, + ResponseEntity deleteMetadata(@PathVariable("distributionSetId") final Long distributionSetId, @PathVariable("metadataKey") final String metadataKey); /** @@ -290,9 +284,8 @@ public interface DistributionSetRestApi { @RequestMapping(method = RequestMethod.POST, value = "/{distributionSetId}/metadata", consumes = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }, produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity> createMetadata( - @PathVariable("distributionSetId") final Long distributionSetId, - @RequestBody final List metadataRest); + ResponseEntity> createMetadata(@PathVariable("distributionSetId") final Long distributionSetId, + @RequestBody final List metadataRest); /** * Assigns a list of software modules to a distribution set. @@ -303,15 +296,12 @@ public interface DistributionSetRestApi { * the list of software modules ids to assign * @return http status * - * @throws EntityNotFoundException - * in case no distribution set with the given - * {@code distributionSetId} exists. */ @RequestMapping(method = RequestMethod.POST, value = "/{distributionSetId}/assignedSM", consumes = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity assignSoftwareModules(@PathVariable("distributionSetId") final Long distributionSetId, - @RequestBody final List softwareModuleIDs); + ResponseEntity assignSoftwareModules(@PathVariable("distributionSetId") final Long distributionSetId, + @RequestBody final List softwareModuleIDs); /** * Deletes the assignment of the software module form the distribution set. @@ -323,13 +313,9 @@ public interface DistributionSetRestApi { * the software module id to get rejected form the distribution * set * @return status OK if rejection was successful. - * @throws EntityNotFoundException - * in case no distribution set with the given - * {@code distributionSetId} exists. */ @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetId}/assignedSM/{softwareModuleId}") - public ResponseEntity deleteAssignSoftwareModules( - @PathVariable("distributionSetId") final Long distributionSetId, + ResponseEntity deleteAssignSoftwareModules(@PathVariable("distributionSetId") final Long distributionSetId, @PathVariable("softwareModuleId") final Long softwareModuleId); /** @@ -349,15 +335,12 @@ public interface DistributionSetRestApi { * {@code field:direction, field:direction} * @return a list of the assigned software modules of a distribution set * with status OK, if none is assigned than {@code null} - * @throws EntityNotFoundException - * in case no distribution set with the given - * {@code distributionSetId} exists. */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/assignedSM", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getAssignedSoftwareModules( + ResponseEntity> getAssignedSoftwareModules( @PathVariable("distributionSetId") final Long distributionSetId, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam); + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam); } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetTagRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTagRestApi.java similarity index 61% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetTagRestApi.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTagRestApi.java index 83f29bb17..5a836ef55 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetTagRestApi.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTagRestApi.java @@ -6,17 +6,16 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.api; +package org.eclipse.hawkbit.mgmt.rest.api; import java.util.List; -import org.eclipse.hawkbit.rest.resource.RestConstants; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest; -import org.eclipse.hawkbit.rest.resource.model.tag.AssignedDistributionSetRequestBody; -import org.eclipse.hawkbit.rest.resource.model.tag.DistributionSetTagAssigmentResultRest; -import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.tag.TagRest; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedDistributionSetRequestBody; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtDistributionSetTagAssigmentResult; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -29,8 +28,8 @@ import org.springframework.web.bind.annotation.RequestParam; * REST Resource handling for DistributionSetTag CRUD operations. * */ -@RequestMapping(RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING) -public interface DistributionSetTagRestApi { +@RequestMapping(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING) +public interface MgmtDistributionSetTagRestApi { /** * Handles the GET request of retrieving all DistributionSet tags. * @@ -52,11 +51,11 @@ public interface DistributionSetTagRestApi { * JsonResponseExceptionHandler is handling the response. */ @RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getDistributionSetTags( - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + ResponseEntity> getDistributionSetTags( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the GET request of retrieving a single distribution set tag. @@ -65,13 +64,10 @@ public interface DistributionSetTagRestApi { * the ID of the distribution set tag to retrieve * * @return a single distribution set tag with status OK. - * @throws EntityNotFoundException - * in case the given {@code distributionsetTagId} doesn't - * exists. */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionsetTagId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getDistributionSetTag( + ResponseEntity getDistributionSetTag( @PathVariable("distributionsetTagId") final Long distributionsetTagId); /** @@ -86,7 +82,7 @@ public interface DistributionSetTagRestApi { */ @RequestMapping(method = RequestMethod.POST, consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> createDistributionSetTags(@RequestBody final List tags); + ResponseEntity> createDistributionSetTags(@RequestBody final List tags); /** * @@ -98,15 +94,12 @@ public interface DistributionSetTagRestApi { * the the request body to be updated * @return status OK if update is successful and the updated distribution * set tag. - * @throws EntityNotFoundException - * in case the given {@code distributionsetTagId} doesn't - * exists. */ @RequestMapping(method = RequestMethod.PUT, value = "/{distributionsetTagId}", consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity updateDistributionSetTag( + ResponseEntity updateDistributionSetTag( @PathVariable("distributionsetTagId") final Long distributionsetTagId, - @RequestBody final TagRequestBodyPut restDSTagRest); + @RequestBody final MgmtTagRequestBodyPut restDSTagRest); /** * Handles the DELETE request for a single distribution set tag. @@ -114,13 +107,10 @@ public interface DistributionSetTagRestApi { * @param distributionsetTagId * the ID of the distribution set tag * @return status OK if delete as successfully. - * @throws EntityNotFoundException - * in case the given {@code distributionsetTagId} doesn't - * exists. * */ @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionsetTagId}") - public ResponseEntity deleteDistributionSetTag( + ResponseEntity deleteDistributionSetTag( @PathVariable("distributionsetTagId") final Long distributionsetTagId); /** @@ -131,12 +121,9 @@ public interface DistributionSetTagRestApi { * the ID of the distribution set tag * * @return the list of assigned distribution sets. - * @throws EntityNotFoundException - * in case the given {@code distributionsetTagId} doesn't - * exists. */ - @RequestMapping(method = RequestMethod.GET, value = RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING) - public ResponseEntity> getAssignedDistributionSets( + @RequestMapping(method = RequestMethod.GET, value = MgmtRestConstants.DISTRIBUTIONSET_REQUEST_MAPPING) + ResponseEntity> getAssignedDistributionSets( @PathVariable("distributionsetTagId") final Long distributionsetTagId); /** @@ -150,15 +137,12 @@ public interface DistributionSetTagRestApi { * * @return the list of assigned distribution sets and unassigned * distribution sets. - * @throws EntityNotFoundException - * in case the given {@code distributionsetTagId} doesn't - * exists. */ - @RequestMapping(method = RequestMethod.POST, value = RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING + @RequestMapping(method = RequestMethod.POST, value = MgmtRestConstants.DISTRIBUTIONSET_REQUEST_MAPPING + "/toggleTagAssignment") - public ResponseEntity toggleTagAssignment( + ResponseEntity toggleTagAssignment( @PathVariable("distributionsetTagId") final Long distributionsetTagId, - @RequestBody final List assignedDSRequestBodies); + @RequestBody final List assignedDSRequestBodies); /** * Handles the POST request to assign distribution sets to the given tag id. @@ -169,14 +153,11 @@ public interface DistributionSetTagRestApi { * list of distribution sets ids to be assigned * * @return the list of assigned distribution set. - * @throws EntityNotFoundException - * in case the given {@code distributionsetTagId} doesn't - * exists. */ - @RequestMapping(method = RequestMethod.POST, value = RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING) - public ResponseEntity> assignDistributionSets( + @RequestMapping(method = RequestMethod.POST, value = MgmtRestConstants.DISTRIBUTIONSET_REQUEST_MAPPING) + ResponseEntity> assignDistributionSets( @PathVariable("distributionsetTagId") final Long distributionsetTagId, - @RequestBody final List assignedDSRequestBodies); + @RequestBody final List assignedDSRequestBodies); /** * Handles the DELETE request to unassign all distribution set from the @@ -185,12 +166,9 @@ public interface DistributionSetTagRestApi { * @param distributionsetTagId * the ID of the distribution set tag to retrieve * @return http status code - * @throws EntityNotFoundException - * in case the given {@code distributionsetTagId} doesn't - * exists. */ - @RequestMapping(method = RequestMethod.DELETE, value = RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING) - public ResponseEntity unassignDistributionSets( + @RequestMapping(method = RequestMethod.DELETE, value = MgmtRestConstants.DISTRIBUTIONSET_REQUEST_MAPPING) + ResponseEntity unassignDistributionSets( @PathVariable("distributionsetTagId") final Long distributionsetTagId); /** @@ -202,13 +180,9 @@ public interface DistributionSetTagRestApi { * @param distributionsetId * the ID of the distribution set to unassign * @return http status code - * @throws EntityNotFoundException - * in case the given {@code distributionsetTagId} doesn't - * exists. */ - @RequestMapping(method = RequestMethod.DELETE, value = RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING + @RequestMapping(method = RequestMethod.DELETE, value = MgmtRestConstants.DISTRIBUTIONSET_REQUEST_MAPPING + "/{distributionsetId}") - public ResponseEntity unassignDistributionSet( - @PathVariable("distributionsetTagId") final Long distributionsetTagId, + ResponseEntity unassignDistributionSet(@PathVariable("distributionsetTagId") final Long distributionsetTagId, @PathVariable("distributionsetId") final Long distributionsetId); } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetTypeRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTypeRestApi.java similarity index 71% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetTypeRestApi.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTypeRestApi.java index 1900d8d7d..25468739e 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetTypeRestApi.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTypeRestApi.java @@ -6,17 +6,16 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.api; +package org.eclipse.hawkbit.mgmt.rest.api; import java.util.List; -import org.eclipse.hawkbit.rest.resource.RestConstants; -import org.eclipse.hawkbit.rest.resource.model.IdRest; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRest; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtId; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType; +import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPut; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -30,8 +29,8 @@ import org.springframework.web.bind.annotation.RequestParam; * operations. * */ -@RequestMapping(RestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING) -public interface DistributionSetTypeRestApi { +@RequestMapping(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING) +public interface MgmtDistributionSetTypeRestApi { /** * Handles the GET request of retrieving all DistributionSetTypes. @@ -55,11 +54,11 @@ public interface DistributionSetTypeRestApi { * response. */ @RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getDistributionSetTypes( - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + ResponseEntity> getDistributionSetTypes( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the GET request of retrieving a single DistributionSetType @@ -69,12 +68,10 @@ public interface DistributionSetTypeRestApi { * the ID of the module type to retrieve * * @return a single softwareModule with status OK. - * @throws EntityNotFoundException - * in case no with the given {@code softwareModuleId} exists. */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getDistributionSetType( + ResponseEntity getDistributionSetType( @PathVariable("distributionSetTypeId") final Long distributionSetTypeId); /** @@ -86,7 +83,7 @@ public interface DistributionSetTypeRestApi { * */ @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetTypeId}") - public ResponseEntity deleteDistributionSetType( + ResponseEntity deleteDistributionSetType( @PathVariable("distributionSetTypeId") final Long distributionSetTypeId); /** @@ -100,9 +97,9 @@ public interface DistributionSetTypeRestApi { */ @RequestMapping(method = RequestMethod.PUT, value = "/{distributionSetTypeId}", consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity updateDistributionSetType( + ResponseEntity updateDistributionSetType( @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, - @RequestBody final DistributionSetTypeRequestBodyPut restDistributionSetType); + @RequestBody final MgmtDistributionSetTypeRequestBodyPut restDistributionSetType); /** * Handles the POST request of creating new DistributionSetTypes. The @@ -117,8 +114,8 @@ public interface DistributionSetTypeRestApi { */ @RequestMapping(method = RequestMethod.POST, consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> createDistributionSetTypes( - @RequestBody final List distributionSetTypes); + ResponseEntity> createDistributionSetTypes( + @RequestBody final List distributionSetTypes); /** * Handles the GET request of retrieving the list of mandatory software @@ -129,9 +126,9 @@ public interface DistributionSetTypeRestApi { * @return Unpaged list of module types and OK in case of success. */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES, produces = { "application/hal+json", + + MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getMandatoryModules( + ResponseEntity> getMandatoryModules( @PathVariable("distributionSetTypeId") final Long distributionSetTypeId); /** @@ -145,9 +142,9 @@ public interface DistributionSetTypeRestApi { * @return Unpaged list of module types and OK in case of success. */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES + + MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getMandatoryModule( + ResponseEntity getMandatoryModule( @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); @@ -162,9 +159,9 @@ public interface DistributionSetTypeRestApi { * @return Unpaged list of module types and OK in case of success. */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES + + MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getOptionalModule( + ResponseEntity getOptionalModule( @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); @@ -177,9 +174,9 @@ public interface DistributionSetTypeRestApi { * @return Unpaged list of module types and OK in case of success. */ @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES, produces = { "application/hal+json", + + MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getOptionalModules( + ResponseEntity> getOptionalModules( @PathVariable("distributionSetTypeId") final Long distributionSetTypeId); /** @@ -194,10 +191,9 @@ public interface DistributionSetTypeRestApi { * @return OK if the request was successful */ @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES + + MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity removeMandatoryModule( - @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + ResponseEntity removeMandatoryModule(@PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); /** @@ -212,10 +208,9 @@ public interface DistributionSetTypeRestApi { * @return OK if the request was successful */ @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES + + MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity removeOptionalModule( - @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + ResponseEntity removeOptionalModule(@PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); /** @@ -230,11 +225,11 @@ public interface DistributionSetTypeRestApi { * @return OK if the request was successful */ @RequestMapping(method = RequestMethod.POST, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES, consumes = { "application/hal+json", + + MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES, consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity addMandatoryModule( - @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @RequestBody final IdRest smtId); + ResponseEntity addMandatoryModule(@PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @RequestBody final MgmtId smtId); /** * Handles the POST request for adding an optional software module type to a @@ -248,10 +243,10 @@ public interface DistributionSetTypeRestApi { * @return OK if the request was successful */ @RequestMapping(method = RequestMethod.POST, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES, consumes = { "application/hal+json", + + MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES, consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity addOptionalModule( - @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @RequestBody final IdRest smtId); + ResponseEntity addOptionalModule(@PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @RequestBody final MgmtId smtId); } diff --git a/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDownloadArtifactRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDownloadArtifactRestApi.java new file mode 100644 index 000000000..ea6dccc7e --- /dev/null +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDownloadArtifactRestApi.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.mgmt.rest.api; + +import java.io.InputStream; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * + */ +@RequestMapping(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) +public interface MgmtDownloadArtifactRestApi { + + /** + * Handles the GET request for downloading an artifact. + * + * @param softwareModuleId + * of the parent SoftwareModule + * @param artifactId + * of the related LocalArtifact + * @param servletResponse + * of the servlet + * @param request + * of the client + * + * @return responseEntity with status ok if successful + */ + @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/artifacts/{artifactId}/download") + @ResponseBody + ResponseEntity downloadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("artifactId") final Long artifactId); + +} diff --git a/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDownloadRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDownloadRestApi.java new file mode 100644 index 000000000..52cd1c991 --- /dev/null +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDownloadRestApi.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.mgmt.rest.api; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * A resource for download artifacts. + * + */ +@RequestMapping(MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE) +public interface MgmtDownloadRestApi { + + /** + * Handles the GET request for downloading an artifact. + * + * @param downloadId + * the generated download id + * @param response + * of the servlet + * @return {@link ResponseEntity} with status {@link HttpStatus#OK} if + * successful + */ + @RequestMapping(method = RequestMethod.GET, value = MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING) + @ResponseBody + ResponseEntity downloadArtifactByDownloadId(@PathVariable("downloadId") final String downloadId); + +} diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/RestConstants.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java similarity index 97% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/RestConstants.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java index bde96f7a8..e8c25403f 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/RestConstants.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java @@ -6,31 +6,19 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.api; /** * Constants for RESTful API. * - * - * */ -public final class RestConstants { +public final class MgmtRestConstants { /** * API version definition. We are using only major versions. */ public static final String API_VERSION = "v1"; - /** - * The base URL mapping for the spring acuator management context path. - */ - public static final String BASE_SYSTEM_MAPPING = "/system"; - - /** - * URL mapping for system admin operations. - */ - public static final String SYSTEM_ADMIN_MAPPING = BASE_SYSTEM_MAPPING + "/admin"; - /** * The base URL mapping of the SP rest resources. */ @@ -50,6 +38,77 @@ public final class RestConstants { */ public static final String REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT = "50"; + /** + * The software module URL mapping rest resource. + */ + public static final String SOFTWAREMODULE_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/softwaremodules"; + + public static final String DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE = "/api/" + API_VERSION + "/downloadserver/"; + + public static final String DOWNLOAD_ID_V1_REQUEST_MAPPING = "downloadId/{downloadId}"; + + /** + * The base URL mapping for the spring acuator management context path. + */ + public static final String BASE_SYSTEM_MAPPING = "/system"; + + /** + * URL mapping for system admin operations. + */ + public static final String SYSTEM_ADMIN_MAPPING = BASE_SYSTEM_MAPPING + "/admin"; + + public static final String SYSTEM_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + BASE_SYSTEM_MAPPING; + + /** + * The target URL mapping, href link for assigned distribution set. + */ + public static final String TARGET_V1_ASSIGNED_DISTRIBUTION_SET = "assignedDS"; + /** + * The target URL mapping, href link for installed distribution set. + */ + public static final String TARGET_V1_INSTALLED_DISTRIBUTION_SET = "installedDS"; + /** + * The target URL mapping, href link for target attributes. + */ + public static final String TARGET_V1_ATTRIBUTES = "attributes"; + /** + * The target URL mapping, href link for target actions. + */ + public static final String TARGET_V1_ACTIONS = "actions"; + /** + * The target URL mapping, href link for canceled actions. + */ + public static final String TARGET_V1_CANCELED_ACTION = "canceledaction"; + /** + * The target URL mapping, href link for canceled actions. + */ + public static final String TARGET_V1_ACTION_STATUS = "status"; + + /** + * The target URL mapping rest resource. + */ + public static final String TARGET_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/targets"; + + /** + * The tag URL mapping rest resource. + */ + public static final String TARGET_TAG_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/targettags"; + /** + * The tag URL mapping rest resource. + */ + public static final String TARGET_TAG_TAGERTS_REQUEST_MAPPING = "/{targetTagId}/targets"; + + /** + * The tag URL mapping rest resource. + */ + public static final String DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + + "/distributionsettags"; + + /** + * The tag URL mapping rest resource. + */ + public static final String DISTRIBUTIONSET_REQUEST_MAPPING = "/{distributionsetTagId}/distributionsets"; + /** * The default offset parameter in case the offset parameter is not present * in the request. @@ -87,62 +146,6 @@ public final class RestConstants { */ public static final String REQUEST_PARAMETER_SEARCH = "q"; - /** - * The target URL mapping, href link for assigned distribution set. - */ - public static final String TARGET_V1_ASSIGNED_DISTRIBUTION_SET = "assignedDS"; - /** - * The target URL mapping, href link for installed distribution set. - */ - public static final String TARGET_V1_INSTALLED_DISTRIBUTION_SET = "installedDS"; - /** - * The target URL mapping, href link for target attributes. - */ - public static final String TARGET_V1_ATTRIBUTES = "attributes"; - /** - * The target URL mapping, href link for target actions. - */ - public static final String TARGET_V1_ACTIONS = "actions"; - /** - * The target URL mapping, href link for canceled actions. - */ - public static final String TARGET_V1_CANCELED_ACTION = "canceledaction"; - /** - * The target URL mapping, href link for canceled actions. - */ - public static final String TARGET_V1_ACTION_STATUS = "status"; - - /** - * The target URL mapping rest resource. - */ - public static final String TARGET_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/targets"; - - public static final String SYSTEM_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/system"; - /** - * The software module URL mapping rest resource. - */ - public static final String SOFTWAREMODULE_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/softwaremodules"; - - /** - * The tag URL mapping rest resource. - */ - public static final String TARGET_TAG_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/targettags"; - /** - * The tag URL mapping rest resource. - */ - public static final String TARGET_TAG_TAGERTS_REQUEST_MAPPING = "/{targetTagId}/targets"; - - /** - * The tag URL mapping rest resource. - */ - public static final String DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING - + "/distributionsettags"; - - /** - * The tag URL mapping rest resource. - */ - public static final String DISTRIBUTIONSET_REQUEST_MAPPING = "/{distributionsetTagId}/distributionsets"; - /** * The software module type URL mapping rest resource. */ @@ -184,11 +187,8 @@ public final class RestConstants { public static final String DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES = "mandatorymoduletypes"; - public static final String DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE = "/api/" + API_VERSION + "/downloadserver/"; - public static final String DOWNLOAD_ID_V1_REQUEST_MAPPING = "downloadId/{downloadId}"; - // constant class, private constructor. - private RestConstants() { + private MgmtRestConstants() { } } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/RolloutRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRolloutRestApi.java similarity index 64% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/RolloutRestApi.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRolloutRestApi.java index 9f76b6bce..7f93e2ce8 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/RolloutRestApi.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRolloutRestApi.java @@ -6,14 +6,13 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.api; +package org.eclipse.hawkbit.mgmt.rest.api; -import org.eclipse.hawkbit.rest.resource.RestConstants; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutResponseBody; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutRestRequestBody; -import org.eclipse.hawkbit.rest.resource.model.rolloutgroup.RolloutGroupResponseBody; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBody; +import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroupResponseBody; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -26,8 +25,8 @@ import org.springframework.web.bind.annotation.RequestParam; * REST Resource handling rollout CRUD operations. * */ -@RequestMapping(RestConstants.ROLLOUT_V1_REQUEST_MAPPING) -public interface RolloutRestApi { +@RequestMapping(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING) +public interface MgmtRolloutRestApi { /** * Handles the GET request of retrieving all rollouts. @@ -49,11 +48,11 @@ public interface RolloutRestApi { * JsonResponseExceptionHandler is handling the response. */ @RequestMapping(method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity> getRollouts( - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + ResponseEntity> getRollouts( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the GET request of retrieving a single rollout. @@ -61,12 +60,10 @@ public interface RolloutRestApi { * @param rolloutId * the ID of the rollout to retrieve * @return a single rollout with status OK. - * @throws EntityNotFoundException - * in case no rollout with the given {@code rolloutId} exists. */ @RequestMapping(value = "/{rolloutId}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity getRollout(@PathVariable("rolloutId") final Long rolloutId); + ResponseEntity getRollout(@PathVariable("rolloutId") final Long rolloutId); /** * Handles the POST request for creating rollout. @@ -77,11 +74,10 @@ public interface RolloutRestApi { * status code 201 with the successfully created rollout. In any * failure the JsonResponseExceptionHandler is handling the * response. - * @throws EntityNotFoundException */ @RequestMapping(method = RequestMethod.POST, consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity create(@RequestBody final RolloutRestRequestBody rolloutRequestBody); + ResponseEntity create(@RequestBody final MgmtRolloutRestRequestBody rolloutRequestBody); /** * Handles the POST request for starting a rollout. @@ -90,14 +86,11 @@ public interface RolloutRestApi { * the ID of the rollout to be started. * @return OK response (200) if rollout could be started. In case of any * exception the corresponding errors occur. - * @throws EntityNotFoundException - * @see RolloutManagement#startRollout(Rollout) - * @see ResponseExceptionHandler */ @RequestMapping(method = RequestMethod.POST, value = "/{rolloutId}/start", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity start(@PathVariable("rolloutId") final Long rolloutId, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_ASYNC, defaultValue = "false") final boolean startAsync); + ResponseEntity start(@PathVariable("rolloutId") final Long rolloutId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_ASYNC, defaultValue = "false") final boolean startAsync); /** * Handles the POST request for pausing a rollout. @@ -106,13 +99,10 @@ public interface RolloutRestApi { * the ID of the rollout to be paused. * @return OK response (200) if rollout could be paused. In case of any * exception the corresponding errors occur. - * @throws EntityNotFoundException - * @see RolloutManagement#pauseRollout(Rollout) - * @see ResponseExceptionHandler */ @RequestMapping(method = RequestMethod.POST, value = "/{rolloutId}/pause", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity pause(@PathVariable("rolloutId") final Long rolloutId); + ResponseEntity pause(@PathVariable("rolloutId") final Long rolloutId); /** * Handles the POST request for resuming a rollout. @@ -121,13 +111,10 @@ public interface RolloutRestApi { * the ID of the rollout to be resumed. * @return OK response (200) if rollout could be resumed. In case of any * exception the corresponding errors occur. - * @throws EntityNotFoundException - * @see RolloutManagement#resumeRollout(Rollout) - * @see ResponseExceptionHandler */ @RequestMapping(method = RequestMethod.POST, value = "/{rolloutId}/resume", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity resume(@PathVariable("rolloutId") final Long rolloutId); + ResponseEntity resume(@PathVariable("rolloutId") final Long rolloutId); /** * Handles the GET request of retrieving all rollout groups referred to a @@ -153,12 +140,12 @@ public interface RolloutRestApi { */ @RequestMapping(method = RequestMethod.GET, value = "/{rolloutId}/deploygroups", produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity> getRolloutGroups( + ResponseEntity> getRolloutGroups( @PathVariable("rolloutId") final Long rolloutId, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the GET request for retrieving a single rollout group. @@ -167,12 +154,11 @@ public interface RolloutRestApi { * the rolloutId to retrieve the group from * @param groupId * the groupId to retrieve the rollout group - * @return the OK response containing the RolloutGroupResponseBody - * @throws EntityNotFoundException + * @return the OK response containing the MgmtRolloutGroupResponseBody */ @RequestMapping(method = RequestMethod.GET, value = "/{rolloutId}/deploygroups/{groupId}", produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity getRolloutGroup(@PathVariable("rolloutId") final Long rolloutId, + ResponseEntity getRolloutGroup(@PathVariable("rolloutId") final Long rolloutId, @PathVariable("groupId") final Long groupId); /** @@ -200,10 +186,10 @@ public interface RolloutRestApi { */ @RequestMapping(method = RequestMethod.GET, value = "/{rolloutId}/deploygroups/{groupId}/targets", produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity> getRolloutGroupTargets(@PathVariable("rolloutId") final Long rolloutId, + ResponseEntity> getRolloutGroupTargets(@PathVariable("rolloutId") final Long rolloutId, @PathVariable("groupId") final Long groupId, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleRestAPI.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleRestApi.java similarity index 73% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleRestAPI.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleRestApi.java index 0eb874489..cdd63ee26 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleRestAPI.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleRestApi.java @@ -6,17 +6,16 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.api; +package org.eclipse.hawkbit.mgmt.rest.api; import java.util.List; -import org.eclipse.hawkbit.rest.resource.RestConstants; -import org.eclipse.hawkbit.rest.resource.model.MetadataRest; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactRest; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRest; +import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPut; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -32,8 +31,8 @@ import org.springframework.web.multipart.MultipartFile; * operations. * */ -@RequestMapping(RestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) -public interface SoftwareModuleRestAPI { +@RequestMapping(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) +public interface MgmtSoftwareModuleRestApi { /** * Handles POST request for artifact upload. @@ -56,7 +55,7 @@ public interface SoftwareModuleRestAPI { */ @RequestMapping(method = RequestMethod.POST, value = "/{softwareModuleId}/artifacts", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity uploadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, + ResponseEntity uploadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, @RequestParam("file") final MultipartFile file, @RequestParam(value = "filename", required = false) final String optionalFileName, @RequestParam(value = "md5sum", required = false) final String md5Sum, @@ -76,8 +75,7 @@ public interface SoftwareModuleRestAPI { @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/artifacts", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) @ResponseBody - public ResponseEntity> getArtifacts( - @PathVariable("softwareModuleId") final Long softwareModuleId); + ResponseEntity> getArtifacts(@PathVariable("softwareModuleId") final Long softwareModuleId); /** * Handles the GET request of retrieving a single Artifact meta data @@ -93,7 +91,7 @@ public interface SoftwareModuleRestAPI { @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/artifacts/{artifactId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) @ResponseBody - public ResponseEntity getArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, + ResponseEntity getArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, @PathVariable("artifactId") final Long artifactId); /** @@ -108,7 +106,7 @@ public interface SoftwareModuleRestAPI { */ @RequestMapping(method = RequestMethod.DELETE, value = "/{softwareModuleId}/artifacts/{artifactId}") @ResponseBody - public ResponseEntity deleteArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, + ResponseEntity deleteArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, @PathVariable("artifactId") final Long artifactId); /** @@ -132,11 +130,11 @@ public interface SoftwareModuleRestAPI { * JsonResponseExceptionHandler is handling the response. */ @RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getSoftwareModules( - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + ResponseEntity> getSoftwareModules( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the GET request of retrieving a single software module. @@ -145,13 +143,10 @@ public interface SoftwareModuleRestAPI { * the ID of the module to retrieve * * @return a single softwareModule with status OK. - * @throws EntityNotFoundException - * in case no with the given {@code softwareModuleId} exists. */ @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getSoftwareModule( - @PathVariable("softwareModuleId") final Long softwareModuleId); + ResponseEntity getSoftwareModule(@PathVariable("softwareModuleId") final Long softwareModuleId); /** * Handles the POST request of creating new softwaremodules. The request @@ -166,8 +161,8 @@ public interface SoftwareModuleRestAPI { */ @RequestMapping(method = RequestMethod.POST, consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> createSoftwareModules( - @RequestBody final List softwareModules); + ResponseEntity> createSoftwareModules( + @RequestBody final List softwareModules); /** * Handles the PUT request of updating a software module. @@ -180,9 +175,9 @@ public interface SoftwareModuleRestAPI { */ @RequestMapping(method = RequestMethod.PUT, value = "/{softwareModuleId}", consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity updateSoftwareModule( + ResponseEntity updateSoftwareModule( @PathVariable("softwareModuleId") final Long softwareModuleId, - @RequestBody final SoftwareModuleRequestBodyPut restSoftwareModule); + @RequestBody final MgmtSoftwareModuleRequestBodyPut restSoftwareModule); /** * Handles the DELETE request for a single software module. @@ -193,7 +188,7 @@ public interface SoftwareModuleRestAPI { * */ @RequestMapping(method = RequestMethod.DELETE, value = "/{softwareModuleId}") - public ResponseEntity deleteSoftwareModule(@PathVariable("softwareModuleId") final Long softwareModuleId); + ResponseEntity deleteSoftwareModule(@PathVariable("softwareModuleId") final Long softwareModuleId); /** * Gets a paged list of meta data for a software module. @@ -217,12 +212,11 @@ public interface SoftwareModuleRestAPI { */ @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/metadata", produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity> getMetadata( - @PathVariable("softwareModuleId") final Long softwareModuleId, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + ResponseEntity> getMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Gets a single meta data value for a specific key of a software module. @@ -236,7 +230,7 @@ public interface SoftwareModuleRestAPI { */ @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/metadata/{metadataKey}", produces = { MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getMetadataValue(@PathVariable("softwareModuleId") final Long softwareModuleId, + ResponseEntity getMetadataValue(@PathVariable("softwareModuleId") final Long softwareModuleId, @PathVariable("metadataKey") final String metadataKey); /** @@ -251,8 +245,8 @@ public interface SoftwareModuleRestAPI { */ @RequestMapping(method = RequestMethod.PUT, value = "/{softwareModuleId}/metadata/{metadataKey}", produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity updateMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId, - @PathVariable("metadataKey") final String metadataKey, @RequestBody final MetadataRest metadata); + ResponseEntity updateMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadata metadata); /** * Deletes a single meta data entry from the software module. @@ -264,7 +258,7 @@ public interface SoftwareModuleRestAPI { * @return status OK if the delete request is successful */ @RequestMapping(method = RequestMethod.DELETE, value = "/{softwareModuleId}/metadata/{metadataKey}") - public ResponseEntity deleteMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId, + ResponseEntity deleteMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId, @PathVariable("metadataKey") final String metadataKey); /** @@ -280,8 +274,7 @@ public interface SoftwareModuleRestAPI { @RequestMapping(method = RequestMethod.POST, value = "/{softwareModuleId}/metadata", consumes = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }, produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity> createMetadata( - @PathVariable("softwareModuleId") final Long softwareModuleId, - @RequestBody final List metadataRest); + ResponseEntity> createMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId, + @RequestBody final List metadataRest); } diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleTypeRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleTypeRestApi.java similarity index 69% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleTypeRestApi.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleTypeRestApi.java index a98e35a32..3fe32d9ad 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleTypeRestApi.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleTypeRestApi.java @@ -6,15 +6,14 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.api; +package org.eclipse.hawkbit.mgmt.rest.api; import java.util.List; -import org.eclipse.hawkbit.rest.resource.RestConstants; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRest; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPut; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -28,8 +27,8 @@ import org.springframework.web.bind.annotation.RequestParam; * operations. * */ -@RequestMapping(RestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING) -public interface SoftwareModuleTypeRestApi { +@RequestMapping(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING) +public interface MgmtSoftwareModuleTypeRestApi { /** * Handles the GET request of retrieving all SoftwareModuleTypes . * @@ -51,11 +50,11 @@ public interface SoftwareModuleTypeRestApi { * JsonResponseExceptionHandler is handling the response. */ @RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getTypes( - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + ResponseEntity> getTypes( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the GET request of retrieving a single software module type . @@ -64,12 +63,10 @@ public interface SoftwareModuleTypeRestApi { * the ID of the module type to retrieve * * @return a single softwareModule with status OK. - * @throws EntityNotFoundException - * in case no with the given {@code softwareModuleId} exists. */ @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getSoftwareModuleType( + ResponseEntity getSoftwareModuleType( @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); /** @@ -81,7 +78,7 @@ public interface SoftwareModuleTypeRestApi { * */ @RequestMapping(method = RequestMethod.DELETE, value = "/{softwareModuleTypeId}") - public ResponseEntity deleteSoftwareModuleType( + ResponseEntity deleteSoftwareModuleType( @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); /** @@ -95,9 +92,9 @@ public interface SoftwareModuleTypeRestApi { */ @RequestMapping(method = RequestMethod.PUT, value = "/{softwareModuleTypeId}", consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity updateSoftwareModuleType( + ResponseEntity updateSoftwareModuleType( @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId, - @RequestBody final SoftwareModuleTypeRequestBodyPut restSoftwareModuleType); + @RequestBody final MgmtSoftwareModuleTypeRequestBodyPut restSoftwareModuleType); /** * Handles the POST request of creating new SoftwareModuleTypes. The request @@ -112,7 +109,7 @@ public interface SoftwareModuleTypeRestApi { */ @RequestMapping(method = RequestMethod.POST, consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> createSoftwareModuleTypes( - @RequestBody final List softwareModuleTypes); + ResponseEntity> createSoftwareModuleTypes( + @RequestBody final List softwareModuleTypes); } diff --git a/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSystemManagementRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSystemManagementRestApi.java new file mode 100644 index 000000000..d4832aa7d --- /dev/null +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSystemManagementRestApi.java @@ -0,0 +1,64 @@ +/** + * 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.mgmt.rest.api; + +import java.util.Collection; + +import org.eclipse.hawkbit.mgmt.json.model.systemmanagement.MgmtSystemCache; +import org.eclipse.hawkbit.mgmt.json.model.systemmanagement.MgmtSystemStatisticsRest; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * System management capabilities by REST. + * + */ +@RequestMapping(MgmtRestConstants.SYSTEM_ADMIN_MAPPING) +public interface MgmtSystemManagementRestApi { + + /** + * Deletes the tenant data of a given tenant. USE WITH CARE! + * + * @param tenant + * to delete + * @return HttpStatus.OK + */ + @RequestMapping(method = RequestMethod.DELETE, value = "/tenants/{tenant}") + ResponseEntity deleteTenant(@PathVariable("tenant") final String tenant); + + /** + * Collects and returns system usage statistics. It provides a system wide + * overview and tenant based stats. + * + * @return system usage statistics + */ + @RequestMapping(method = RequestMethod.GET, value = "/usage", produces = { "application/hal+json", + MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity getSystemUsageStats(); + + /** + * Returns a list of all caches. + * + * @return a list of caches for all tenants + */ + @RequestMapping(method = RequestMethod.GET, value = "/caches") + ResponseEntity> getCaches(); + + /** + * Invalidates all caches for all tenants. + * + * @return a list of cache names which has been invalidated + */ + @RequestMapping(method = RequestMethod.DELETE, value = "/caches") + ResponseEntity> invalidateCaches(); + +} diff --git a/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSystemRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSystemRestApi.java new file mode 100644 index 000000000..d120759b2 --- /dev/null +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSystemRestApi.java @@ -0,0 +1,88 @@ +/** + * 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.mgmt.rest.api; + +import java.util.Map; + +import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValue; +import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValueRequest; +import org.springframework.hateoas.ResourceSupport; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * REST Resource handling tenant specific configuration operations. + * + * + */ +@RequestMapping(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING) +public interface MgmtSystemRestApi { + + @RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity getSystem(); + + /** + * @return a Map of all configuration values. + */ + @RequestMapping(method = RequestMethod.GET, value = "/configs", produces = { "application/hal+json", + MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity> getSystemConfiguration(); + + /** + * Handles the DELETE request of deleting a tenant specific configuration + * value within SP. + * + * @param keyName + * the Name of the configuration key + * @return If the given configuration value exists and could be deleted Http + * OK. In any failure the JsonResponseExceptionHandler is handling + * the response. + */ + @RequestMapping(method = RequestMethod.DELETE, value = "/configs/{keyName}", produces = { "application/hal+json", + MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity deleteConfigurationValue(@PathVariable("keyName") final String keyName); + + /** + * Handles the GET request of deleting a tenant specific configuration value + * within SP. + * + * @param keyName + * the Name of the configuration key + * @return If the given configuration value exists and could be get Http OK. + * In any failure the JsonResponseExceptionHandler is handling the + * response. + */ + @RequestMapping(method = RequestMethod.GET, value = "/configs/{keyName}", produces = { "application/hal+json", + MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity getConfigurationValue( + @PathVariable("keyName") final String keyName); + + /** + * Handles the GET request of deleting a tenant specific configuration value + * within SP. + * + * @param keyName + * the Name of the configuration key + * @param configurationValueRest + * the new value for the configuration + * @return If the given configuration value exists and could be get Http OK. + * In any failure the JsonResponseExceptionHandler is handling the + * response. + */ + @RequestMapping(method = RequestMethod.PUT, value = "/configs/{keyName}", consumes = { "application/hal+json", + MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity updateConfigurationValue( + @PathVariable("keyName") final String keyName, + @RequestBody final MgmtSystemTenantConfigurationValueRequest configurationValueRest); + +} diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/TargetRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetRestApi.java similarity index 54% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/TargetRestApi.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetRestApi.java index 48e242f81..97a0eae5c 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/TargetRestApi.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetRestApi.java @@ -6,19 +6,18 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.api; +package org.eclipse.hawkbit.mgmt.rest.api; import java.util.List; -import org.eclipse.hawkbit.rest.resource.RestConstants; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.action.ActionRest; -import org.eclipse.hawkbit.rest.resource.model.action.ActionStatusRest; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest; -import org.eclipse.hawkbit.rest.resource.model.target.DistributionSetAssigmentRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetAttributes; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction; +import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionStatus; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtDistributionSetAssigment; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetAttributes; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -30,22 +29,20 @@ import org.springframework.web.bind.annotation.RequestParam; /** * Api for handling target operations. */ -@RequestMapping(RestConstants.TARGET_V1_REQUEST_MAPPING) -public interface TargetRestApi { +@RequestMapping(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING) +public interface MgmtTargetRestApi { /** * Handles the GET request of retrieving a single target. * - * @param targetId + * @param controllerId * the ID of the target to retrieve * @return a single target with status OK. - * @throws EntityNotFoundException - * in case no target with the given {@code targetId} exists. */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetId}", produces = { "application/hal+json", + @RequestMapping(method = RequestMethod.GET, value = "/{controllerId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getTarget(@PathVariable("targetId") final String targetId); + ResponseEntity getTarget(@PathVariable("controllerId") final String controllerId); /** * Handles the GET request of retrieving all targets. @@ -68,11 +65,11 @@ public interface TargetRestApi { */ @RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getTargets( - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + ResponseEntity> getTargets( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the POST request of creating new targets. The request body must @@ -87,14 +84,14 @@ public interface TargetRestApi { */ @RequestMapping(method = RequestMethod.POST, consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> createTargets(@RequestBody final List targets); + ResponseEntity> createTargets(@RequestBody final List targets); /** * Handles the PUT request of updating a target. The ID is within the URL * path of the request. A given ID in the request body is ignored. It's not * possible to set fields to {@code null} values. * - * @param targetId + * @param controllerId * the path parameter which contains the ID of the target * @param targetRest * the request body which contains the fields which should be @@ -103,42 +100,40 @@ public interface TargetRestApi { * @return the updated target response which contains all fields also fields * which have not updated */ - @RequestMapping(method = RequestMethod.PUT, value = "/{targetId}", consumes = { "application/hal+json", + @RequestMapping(method = RequestMethod.PUT, value = "/{controllerId}", consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity updateTarget(@PathVariable("targetId") final String targetId, - @RequestBody final TargetRequestBody targetRest); + ResponseEntity updateTarget(@PathVariable("controllerId") final String controllerId, + @RequestBody final MgmtTargetRequestBody targetRest); /** * Handles the DELETE request of deleting a target. * - * @param targetId + * @param controllerId * the ID of the target to be deleted - * @return If the given targetId could exists and could be deleted Http OK. - * In any failure the JsonResponseExceptionHandler is handling the - * response. + * @return If the given controllerId could exists and could be deleted Http + * OK. In any failure the JsonResponseExceptionHandler is handling + * the response. */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{targetId}", produces = { "application/hal+json", + @RequestMapping(method = RequestMethod.DELETE, value = "/{controllerId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity deleteTarget(@PathVariable("targetId") final String targetId); + ResponseEntity deleteTarget(@PathVariable("controllerId") final String controllerId); /** * Handles the GET request of retrieving the attributes of a specific * target. * - * @param targetId + * @param controllerId * the ID of the target to retrieve the attributes. * @return the target attributes as map response with status OK - * @throws EntityNotFoundException - * in case no target with the given {@code targetId} exists. */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetId}/attributes", produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getAttributes(@PathVariable("targetId") final String targetId); + @RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/attributes", produces = { + "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity getAttributes(@PathVariable("controllerId") final String controllerId); /** * Handles the GET request of retrieving the Actions of a specific target. * - * @param targetId + * @param controllerId * to load actions for * @param pagingOffsetParam * the offset of list of targets for pagination, might not be @@ -156,47 +151,43 @@ public interface TargetRestApi { * status OK. The response is always paged. In any failure the * JsonResponseExceptionHandler is handling the response. */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetId}/actions", produces = { "application/hal+json", + @RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/actions", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getActionHistory(@PathVariable("targetId") final String targetId, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + ResponseEntity> getActionHistory(@PathVariable("controllerId") final String controllerId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the GET request of retrieving a specific Actions of a specific * Target. * - * @param targetId + * @param controllerId * to load the action for * @param actionId * to load * @return the action */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetId}/actions/{actionId}", produces = { + @RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/actions/{actionId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getAction(@PathVariable("targetId") final String targetId, + ResponseEntity getAction(@PathVariable("controllerId") final String controllerId, @PathVariable("actionId") final Long actionId); /** * Handles the DELETE request of canceling an specific Actions of a specific * Target. * - * @param targetId + * @param controllerId * the ID of the target in the URL path parameter * @param actionId * the ID of the action in the URL path parameter * @param force * optional parameter, which indicates a force cancel * @return status no content in case cancellation was successful - * @throws CancelActionNotAllowedException - * if the given action is not active and cannot be canceled. - * @throws EntityNotFoundException - * if the target or the action is not found */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{targetId}/actions/{actionId}") - public ResponseEntity cancelAction(@PathVariable("targetId") final String targetId, + @RequestMapping(method = RequestMethod.DELETE, value = "/{controllerId}/actions/{actionId}") + ResponseEntity cancelAction(@PathVariable("controllerId") final String controllerId, @PathVariable("actionId") final Long actionId, @RequestParam(value = "force", required = false, defaultValue = "false") final boolean force); @@ -204,7 +195,7 @@ public interface TargetRestApi { * Handles the GET request of retrieving the ActionStatus of a specific * target and action. * - * @param targetId + * @param controllerId * of the the action * @param actionId * of the status we are intend to load @@ -221,62 +212,55 @@ public interface TargetRestApi { * with status OK. The response is always paged. In any failure the * JsonResponseExceptionHandler is handling the response. */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetId}/actions/{actionId}/status", produces = { + @RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/actions/{actionId}/status", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getActionStatusList( - @PathVariable("targetId") final String targetId, @PathVariable("actionId") final Long actionId, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam); + ResponseEntity> getActionStatusList( + @PathVariable("controllerId") final String controllerId, @PathVariable("actionId") final Long actionId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam); /** * Handles the GET request of retrieving the assigned distribution set of an * specific target. * - * @param targetId + * @param controllerId * the ID of the target to retrieve the assigned distribution * @return the assigned distribution set with status OK, if none is assigned * than {@code null} content (e.g. "{}") - * @throws EntityNotFoundException - * in case no target with the given {@code targetId} exists. */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetId}/assignedDS", produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getAssignedDistributionSet( - @PathVariable("targetId") final String targetId); + @RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/assignedDS", produces = { + "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity getAssignedDistributionSet( + @PathVariable("controllerId") final String controllerId); /** * Changes the assigned distribution set of a target. * - * @param targetId + * @param controllerId * of the target to change * @param dsId * of the distributionset that is to be assigned * @return http status - * - * @throws EntityNotFoundException - * in case no target with the given {@code targetId} exists. - * */ - @RequestMapping(method = RequestMethod.POST, value = "/{targetId}/assignedDS", consumes = { "application/hal+json", + @RequestMapping(method = RequestMethod.POST, value = "/{controllerId}/assignedDS", consumes = { + "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity postAssignedDistributionSet(@PathVariable("targetId") final String targetId, - @RequestBody final DistributionSetAssigmentRest dsId); + ResponseEntity postAssignedDistributionSet(@PathVariable("controllerId") final String controllerId, + @RequestBody final MgmtDistributionSetAssigment dsId); /** * Handles the GET request of retrieving the installed distribution set of * an specific target. * - * @param targetId + * @param controllerId * the ID of the target to retrieve * @return the assigned installed set with status OK, if none is installed * than {@code null} content (e.g. "{}") - * @throws EntityNotFoundException - * in case no target with the given {@code targetId} exists. */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetId}/installedDS", produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getInstalledDistributionSet( - @PathVariable("targetId") final String targetId); + @RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/installedDS", produces = { + "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity getInstalledDistributionSet( + @PathVariable("controllerId") final String controllerId); -} \ No newline at end of file +} diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/TargetTagRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java similarity index 58% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/TargetTagRestApi.java rename to hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java index 940b578d4..e568e7377 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/TargetTagRestApi.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java @@ -6,17 +6,16 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.api; +package org.eclipse.hawkbit.mgmt.rest.api; import java.util.List; -import org.eclipse.hawkbit.rest.resource.RestConstants; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.tag.AssignedTargetRequestBody; -import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.tag.TagRest; -import org.eclipse.hawkbit.rest.resource.model.tag.TargetTagAssigmentResultRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedTargetRequestBody; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTargetTagAssigmentResult; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -29,8 +28,8 @@ import org.springframework.web.bind.annotation.RequestParam; * REST Resource handling for TargetTag CRUD operations. * */ -@RequestMapping(RestConstants.TARGET_TAG_V1_REQUEST_MAPPING) -public interface TargetTagRestApi { +@RequestMapping(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING) +public interface MgmtTargetTagRestApi { /** * Handles the GET request of retrieving all target tags. @@ -52,11 +51,11 @@ public interface TargetTagRestApi { * JsonResponseExceptionHandler is handling the response. */ @RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getTargetTags( - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); + ResponseEntity> getTargetTags( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam); /** * Handles the GET request of retrieving a single target tag. @@ -65,12 +64,10 @@ public interface TargetTagRestApi { * the ID of the target tag to retrieve * * @return a single target tag with status OK. - * @throws EntityNotFoundException - * in case the given {@code targetTagId} doesn't exists. */ @RequestMapping(method = RequestMethod.GET, value = "/{targetTagId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getTargetTag(@PathVariable("targetTagId") final Long targetTagId); + ResponseEntity getTargetTag(@PathVariable("targetTagId") final Long targetTagId); /** * Handles the POST request of creating new target tag. The request body @@ -84,7 +81,7 @@ public interface TargetTagRestApi { */ @RequestMapping(method = RequestMethod.POST, consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> createTargetTags(@RequestBody final List tags); + ResponseEntity> createTargetTags(@RequestBody final List tags); /** * @@ -95,13 +92,11 @@ public interface TargetTagRestApi { * @param restTargetTagRest * the the request body to be updated * @return status OK if update is successful and the updated target tag. - * @throws EntityNotFoundException - * in case the given {@code targetTagId} doesn't exists. */ @RequestMapping(method = RequestMethod.PUT, value = "/{targetTagId}", consumes = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity updateTagretTag(@PathVariable("targetTagId") final Long targetTagId, - @RequestBody final TagRequestBodyPut restTargetTagRest); + ResponseEntity updateTagretTag(@PathVariable("targetTagId") final Long targetTagId, + @RequestBody final MgmtTagRequestBodyPut restTargetTagRest); /** * Handles the DELETE request for a single target tag. @@ -109,12 +104,10 @@ public interface TargetTagRestApi { * @param targetTagId * the ID of the target tag * @return status OK if delete as successfully. - * @throws EntityNotFoundException - * in case the given {@code targetTagId} doesn't exists. * */ @RequestMapping(method = RequestMethod.DELETE, value = "/{targetTagId}") - public ResponseEntity deleteTargetTag(@PathVariable("targetTagId") final Long targetTagId); + ResponseEntity deleteTargetTag(@PathVariable("targetTagId") final Long targetTagId); /** * Handles the GET request of retrieving all assigned targets by the given @@ -124,11 +117,9 @@ public interface TargetTagRestApi { * the ID of the target tag to retrieve * * @return the list of assigned targets. - * @throws EntityNotFoundException - * in case the given {@code targetTagId} doesn't exists. */ - @RequestMapping(method = RequestMethod.GET, value = RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING) - public ResponseEntity> getAssignedTargets(@PathVariable("targetTagId") final Long targetTagId); + @RequestMapping(method = RequestMethod.GET, value = MgmtRestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING) + ResponseEntity> getAssignedTargets(@PathVariable("targetTagId") final Long targetTagId); /** * Handles the POST request to toggle the assignment of targets by the given @@ -140,14 +131,12 @@ public interface TargetTagRestApi { * list of target ids to be toggled * * @return the list of assigned targets and unassigned targets. - * @throws EntityNotFoundException - * in case the given {@code targetTagId} doesn't exists. */ - @RequestMapping(method = RequestMethod.POST, value = RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING + @RequestMapping(method = RequestMethod.POST, value = MgmtRestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING + "/toggleTagAssignment") - public ResponseEntity toggleTagAssignment( + ResponseEntity toggleTagAssignment( @PathVariable("targetTagId") final Long targetTagId, - @RequestBody final List assignedTargetRequestBodies); + @RequestBody final List assignedTargetRequestBodies); /** * Handles the POST request to assign targets to the given tag id. @@ -158,12 +147,10 @@ public interface TargetTagRestApi { * list of target ids to be assigned * * @return the list of assigned targets. - * @throws EntityNotFoundException - * in case the given {@code targetTagId} doesn't exists. */ - @RequestMapping(method = RequestMethod.POST, value = RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING) - public ResponseEntity> assignTargets(@PathVariable("targetTagId") final Long targetTagId, - @RequestBody final List assignedTargetRequestBodies); + @RequestMapping(method = RequestMethod.POST, value = MgmtRestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING) + ResponseEntity> assignTargets(@PathVariable("targetTagId") final Long targetTagId, + @RequestBody final List assignedTargetRequestBodies); /** * Handles the DELETE request to unassign all targets from the given tag id. @@ -171,11 +158,9 @@ public interface TargetTagRestApi { * @param targetTagId * the ID of the target tag to retrieve * @return http status code - * @throws EntityNotFoundException - * in case the given {@code targetTagId} doesn't exists. */ - @RequestMapping(method = RequestMethod.DELETE, value = RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING) - public ResponseEntity unassignTargets(@PathVariable("targetTagId") final Long targetTagId); + @RequestMapping(method = RequestMethod.DELETE, value = MgmtRestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING) + ResponseEntity unassignTargets(@PathVariable("targetTagId") final Long targetTagId); /** * Handles the DELETE request to unassign one target from the given tag id. @@ -185,11 +170,9 @@ public interface TargetTagRestApi { * @param controllerId * the ID of the target to unassign * @return http status code - * @throws EntityNotFoundException - * in case the given {@code targetTagId} doesn't exists. */ - @RequestMapping(method = RequestMethod.DELETE, value = RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING + @RequestMapping(method = RequestMethod.DELETE, value = MgmtRestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING + "/{controllerId}") - public ResponseEntity unassignTarget(@PathVariable("targetTagId") final Long targetTagId, + ResponseEntity unassignTarget(@PathVariable("targetTagId") final Long targetTagId, @PathVariable("controllerId") final String controllerId); } diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/model/PagedListTest.java b/hawkbit-mgmt-api/src/test/java/org/eclipse/hawkbit/mgmt/json/model/PagedListTest.java similarity index 97% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/model/PagedListTest.java rename to hawkbit-mgmt-api/src/test/java/org/eclipse/hawkbit/mgmt/json/model/PagedListTest.java index 68ce570a1..c17acb3b1 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/model/PagedListTest.java +++ b/hawkbit-mgmt-api/src/test/java/org/eclipse/hawkbit/mgmt/json/model/PagedListTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model; +package org.eclipse.hawkbit.mgmt.json.model; import static org.fest.assertions.Assertions.assertThat; import static org.junit.Assert.fail; diff --git a/hawkbit-mgmt-resource/README.md b/hawkbit-mgmt-resource/README.md new file mode 100644 index 000000000..3bad53d61 --- /dev/null +++ b/hawkbit-mgmt-resource/README.md @@ -0,0 +1,13 @@ +# Eclipse.IoT hawkBit - Mgmt Resource + +This is the server-side implementation of the hawkBit Mgmt API that is used to manage and monitor the HawkBit Update Server via HTTP. + +# Compile + +#### Build hawkbit-mgmt-resource + +``` +$ cd hawkbit/hawkbit-mgmt-resource +$ mvn clean install +``` + diff --git a/hawkbit-rest-resource/pom.xml b/hawkbit-mgmt-resource/pom.xml similarity index 79% rename from hawkbit-rest-resource/pom.xml rename to hawkbit-mgmt-resource/pom.xml index 0be5d20f5..007c6789b 100644 --- a/hawkbit-rest-resource/pom.xml +++ b/hawkbit-mgmt-resource/pom.xml @@ -16,52 +16,56 @@ hawkbit-parent 0.2.0-SNAPSHOT - hawkbit-rest-resource - hawkBit :: REST Resources + hawkbit-mgmt-resource + hawkBit :: REST Mgmt Resources org.eclipse.hawkbit - hawkbit-repository + hawkbit-repository-api ${project.version} - - + + org.eclipse.hawkbit - hawkbit-core + hawkbit-mgmt-api ${project.version} org.eclipse.hawkbit - hawkbit-rest-api + hawkbit-rest-core ${project.version} - - javax.servlet - javax.servlet-api - provided - - - org.apache.tomcat.embed - tomcat-embed-core - provided - - - io.springfox - springfox-core - 2.0.3 - commons-io commons-io 2.4 - org.springframework.security - spring-security-web + org.springframework.plugin + spring-plugin-core + + org.eclipse.hawkbit + hawkbit-repository-test + ${project.version} + test + + + org.eclipse.hawkbit + hawkbit-repository-jpa + ${project.version} + test + + + org.eclipse.hawkbit + hawkbit-rest-core + ${project.version} + tests + test + org.springframework.boot spring-boot-starter @@ -98,13 +102,6 @@ spring-security-config test - - org.eclipse.hawkbit - hawkbit-repository - ${project.version} - tests - test - org.eclipse.hawkbit hawkbit-http-security @@ -161,25 +158,10 @@ allure-junit-adaptor test - + org.springframework spring-context-support test - + - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - \ No newline at end of file diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/EnableMgmtApi.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/EnableMgmtApi.java new file mode 100644 index 000000000..6d4252e55 --- /dev/null +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/EnableMgmtApi.java @@ -0,0 +1,34 @@ +/** + * 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.mgmt; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.eclipse.hawkbit.rest.configuration.RestConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Controller; + +/** + * Annotation to enable {@link ComponentScan} in the resource package to setup + * all {@link Controller} annotated classes and setup the REST-Resources for the + * Management API. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Configuration +@ComponentScan +@Import(RestConfiguration.class) +public @interface EnableMgmtApi { + +} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetMapper.java similarity index 64% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetMapper.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetMapper.java index 8051146a1..4a0f8d90e 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetMapper.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetMapper.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; @@ -14,20 +14,22 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; import java.util.ArrayList; import java.util.List; +import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentResponseBody; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult; import org.eclipse.hawkbit.repository.DistributionSetManagement; +import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.rest.resource.api.DistributionSetRestApi; -import org.eclipse.hawkbit.rest.resource.api.DistributionSetTypeRestApi; -import org.eclipse.hawkbit.rest.resource.model.MetadataRest; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest; -import org.eclipse.hawkbit.rest.resource.model.distributionset.TargetAssignmentResponseBody; /** * A mapper which maps repository model to RESTful model representation and @@ -37,8 +39,8 @@ import org.eclipse.hawkbit.rest.resource.model.distributionset.TargetAssignmentR * * */ -public final class DistributionSetMapper { - private DistributionSetMapper() { +public final class MgmtDistributionSetMapper { + private MgmtDistributionSetMapper() { // Utility class } @@ -65,7 +67,7 @@ public final class DistributionSetMapper { } /** - * {@link DistributionSetRequestBodyPost}s to {@link DistributionSet}s. + * {@link MgmtDistributionSetRequestBodyPost}s to {@link DistributionSet}s. * * @param sets * to convert @@ -73,19 +75,20 @@ public final class DistributionSetMapper { * to use for conversion * @return converted list of {@link DistributionSet}s */ - static List dsFromRequest(final Iterable sets, - final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement) { + static List dsFromRequest(final Iterable sets, + final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement, + final EntityFactory entityFactory) { final List mappedList = new ArrayList<>(); - for (final DistributionSetRequestBodyPost dsRest : sets) { - mappedList.add(fromRequest(dsRest, softwareManagement, distributionSetManagement)); + for (final MgmtDistributionSetRequestBodyPost dsRest : sets) { + mappedList.add(fromRequest(dsRest, softwareManagement, distributionSetManagement, entityFactory)); } return mappedList; } /** - * {@link DistributionSetRequestBodyPost} to {@link DistributionSet}. + * {@link MgmtDistributionSetRequestBodyPost} to {@link DistributionSet}. * * @param dsRest * to convert @@ -93,10 +96,11 @@ public final class DistributionSetMapper { * to use for conversion * @return converted {@link DistributionSet} */ - static DistributionSet fromRequest(final DistributionSetRequestBodyPost dsRest, - final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement) { + static DistributionSet fromRequest(final MgmtDistributionSetRequestBodyPost dsRest, + final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement, + final EntityFactory entityFactory) { - final DistributionSet result = new DistributionSet(); + final DistributionSet result = entityFactory.generateDistributionSet(); result.setDescription(dsRest.getDescription()); result.setName(dsRest.getName()); result.setType(findDistributionSetTypeWithExceptionIfNotFound(dsRest.getType(), distributionSetManagement)); @@ -127,20 +131,21 @@ public final class DistributionSetMapper { } /** - * From {@link MetadataRest} to {@link DistributionSetMetadata}. + * From {@link MgmtMetadata} to {@link DistributionSetMetadata}. * * @param ds * @param metadata * @return */ static List fromRequestDsMetadata(final DistributionSet ds, - final List metadata) { + final List metadata, final EntityFactory entityFactory) { final List mappedList = new ArrayList<>(metadata.size()); - for (final MetadataRest metadataRest : metadata) { + for (final MgmtMetadata metadataRest : metadata) { if (metadataRest.getKey() == null) { throw new IllegalArgumentException("the key of the metadata must be present"); } - mappedList.add(new DistributionSetMetadata(metadataRest.getKey(), ds, metadataRest.getValue())); + mappedList.add( + entityFactory.generateDistributionSetMetadata(ds, metadataRest.getKey(), metadataRest.getValue())); } return mappedList; } @@ -152,12 +157,12 @@ public final class DistributionSetMapper { * the ds set * @return the response */ - public static DistributionSetRest toResponse(final DistributionSet distributionSet) { + public static MgmtDistributionSet toResponse(final DistributionSet distributionSet) { if (distributionSet == null) { return null; } - final DistributionSetRest response = new DistributionSetRest(); - RestModelMapper.mapNamedToNamed(response, distributionSet); + final MgmtDistributionSet response = new MgmtDistributionSet(); + MgmtRestModelMapper.mapNamedToNamed(response, distributionSet); response.setDsId(distributionSet.getId()); response.setVersion(distributionSet.getVersion()); @@ -165,35 +170,34 @@ public final class DistributionSetMapper { response.setType(distributionSet.getType().getKey()); distributionSet.getModules() - .forEach(module -> response.getModules().add(SoftwareModuleMapper.toResponse(module))); + .forEach(module -> response.getModules().add(MgmtSoftwareModuleMapper.toResponse(module))); response.setRequiredMigrationStep(distributionSet.isRequiredMigrationStep()); - response.add( - linkTo(methodOn(DistributionSetRestApi.class).getDistributionSet(response.getDsId())).withRel("self")); + response.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(response.getDsId())) + .withRel("self")); - response.add(linkTo( - methodOn(DistributionSetTypeRestApi.class).getDistributionSetType(distributionSet.getType().getId())) - .withRel("type")); + response.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class) + .getDistributionSetType(distributionSet.getType().getId())).withRel("type")); - response.add(linkTo(methodOn(DistributionSetRestApi.class).getMetadata(response.getDsId(), - Integer.parseInt(RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET), - Integer.parseInt(RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT), null, null)) + response.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getMetadata(response.getDsId(), + Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET), + Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT), null, null)) .withRel("metadata")); return response; } - static TargetAssignmentResponseBody toResponse(final DistributionSetAssignmentResult dsAssignmentResult) { - final TargetAssignmentResponseBody result = new TargetAssignmentResponseBody(); + static MgmtTargetAssignmentResponseBody toResponse(final DistributionSetAssignmentResult dsAssignmentResult) { + final MgmtTargetAssignmentResponseBody result = new MgmtTargetAssignmentResponseBody(); result.setAssigned(dsAssignmentResult.getAssigned()); result.setAlreadyAssigned(dsAssignmentResult.getAlreadyAssigned()); result.setTotal(dsAssignmentResult.getTotal()); return result; } - static List toResponseDistributionSets(final Iterable sets) { - final List response = new ArrayList<>(); + static List toResponseDistributionSets(final Iterable sets) { + final List response = new ArrayList<>(); if (sets != null) { for (final DistributionSet set : sets) { @@ -203,27 +207,27 @@ public final class DistributionSetMapper { return response; } - static MetadataRest toResponseDsMetadata(final DistributionSetMetadata metadata) { - final MetadataRest metadataRest = new MetadataRest(); - metadataRest.setKey(metadata.getId().getKey()); + static MgmtMetadata toResponseDsMetadata(final DistributionSetMetadata metadata) { + final MgmtMetadata metadataRest = new MgmtMetadata(); + metadataRest.setKey(metadata.getKey()); metadataRest.setValue(metadata.getValue()); return metadataRest; } - static List toResponseDsMetadata(final List metadata) { + static List toResponseDsMetadata(final List metadata) { - final List mappedList = new ArrayList<>(metadata.size()); + final List mappedList = new ArrayList<>(metadata.size()); for (final DistributionSetMetadata distributionSetMetadata : metadata) { mappedList.add(toResponseDsMetadata(distributionSetMetadata)); } return mappedList; } - static List toResponseFromDsList(final List sets) { - final List mappedList = new ArrayList<>(); + static List toResponseFromDsList(final List sets) { + final List mappedList = new ArrayList<>(); if (sets != null) { for (final DistributionSet set : sets) { - final DistributionSetRest response = toResponse(set); + final MgmtDistributionSet response = toResponse(set); mappedList.add(response); } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java similarity index 54% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java index 27231308b..e99a33c5f 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java @@ -6,42 +6,39 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPut; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentRequestBody; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentResponseBody; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleAssigment; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult; -import org.eclipse.hawkbit.repository.DistributionSetFields; import org.eclipse.hawkbit.repository.DistributionSetManagement; -import org.eclipse.hawkbit.repository.DistributionSetMetadataFields; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.SystemManagement; -import org.eclipse.hawkbit.repository.TargetFields; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.TargetWithActionType; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; -import org.eclipse.hawkbit.repository.model.DsMetadataCompositeKey; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.rsql.RSQLUtility; -import org.eclipse.hawkbit.rest.resource.api.DistributionSetRestApi; -import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper; -import org.eclipse.hawkbit.rest.resource.model.MetadataRest; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest; -import org.eclipse.hawkbit.rest.resource.model.distributionset.TargetAssignmentRequestBody; -import org.eclipse.hawkbit.rest.resource.model.distributionset.TargetAssignmentResponseBody; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleAssigmentRest; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; +import org.eclipse.hawkbit.repository.model.TargetWithActionType; import org.eclipse.hawkbit.tenancy.TenantAware; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,14 +48,17 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * REST Resource handling for {@link DistributionSet} CRUD operations. */ @RestController -public class DistributionSetResource implements DistributionSetRestApi { - private static final Logger LOG = LoggerFactory.getLogger(DistributionSetResource.class); +public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi { + private static final Logger LOG = LoggerFactory.getLogger(MgmtDistributionSetResource.class); @Autowired private SoftwareManagement softwareManagement; @@ -75,12 +75,18 @@ public class DistributionSetResource implements DistributionSetRestApi { @Autowired private TenantAware currentTenant; + @Autowired + private EntityFactory entityFactory; + @Autowired private DistributionSetManagement distributionSetManagement; @Override - public ResponseEntity> getDistributionSets(final int pagingOffsetParam, - final int pagingLimitParam, final String sortParam, final String rsqlParam) { + public ResponseEntity> getDistributionSets( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -89,41 +95,44 @@ public class DistributionSetResource implements DistributionSetRestApi { final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting); final Page findDsPage; if (rsqlParam != null) { - findDsPage = this.distributionSetManagement.findDistributionSetsAll( - RSQLUtility.parse(rsqlParam, DistributionSetFields.class), pageable, false); + findDsPage = this.distributionSetManagement.findDistributionSetsAll(rsqlParam, pageable, false); } else { - findDsPage = this.distributionSetManagement.findDistributionSetsAll(pageable, false, null); + findDsPage = this.distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageable, false, + null); } - final List rest = DistributionSetMapper.toResponseFromDsList(findDsPage.getContent()); + final List rest = MgmtDistributionSetMapper.toResponseFromDsList(findDsPage.getContent()); return new ResponseEntity<>(new PagedList<>(rest, findDsPage.getTotalElements()), HttpStatus.OK); } @Override - public ResponseEntity getDistributionSet(final Long distributionSetId) { + public ResponseEntity getDistributionSet( + @PathVariable("distributionSetId") final Long distributionSetId) { final DistributionSet foundDs = findDistributionSetWithExceptionIfNotFound(distributionSetId); - return new ResponseEntity<>(DistributionSetMapper.toResponse(foundDs), HttpStatus.OK); + return new ResponseEntity<>(MgmtDistributionSetMapper.toResponse(foundDs), HttpStatus.OK); } @Override - public ResponseEntity> createDistributionSets( - final List sets) { + public ResponseEntity> createDistributionSets( + @RequestBody final List sets) { LOG.debug("creating {} distribution sets", sets.size()); // set default Ds type if ds type is null sets.stream().filter(ds -> ds.getType() == null).forEach(ds -> ds.setType(this.systemManagement .getTenantMetadata(this.currentTenant.getCurrentTenant()).getDefaultDsType().getKey())); - final Iterable createdDSets = this.distributionSetManagement.createDistributionSets( - DistributionSetMapper.dsFromRequest(sets, this.softwareManagement, this.distributionSetManagement)); + final Iterable createdDSets = this.distributionSetManagement + .createDistributionSets(MgmtDistributionSetMapper.dsFromRequest(sets, this.softwareManagement, + this.distributionSetManagement, entityFactory)); LOG.debug("{} distribution sets created, return status {}", sets.size(), HttpStatus.CREATED); - return new ResponseEntity<>(DistributionSetMapper.toResponseDistributionSets(createdDSets), HttpStatus.CREATED); + return new ResponseEntity<>(MgmtDistributionSetMapper.toResponseDistributionSets(createdDSets), + HttpStatus.CREATED); } @Override - public ResponseEntity deleteDistributionSet(final Long distributionSetId) { + public ResponseEntity deleteDistributionSet(@PathVariable("distributionSetId") final Long distributionSetId) { final DistributionSet set = findDistributionSetWithExceptionIfNotFound(distributionSetId); this.distributionSetManagement.deleteDistributionSet(set); @@ -132,8 +141,9 @@ public class DistributionSetResource implements DistributionSetRestApi { } @Override - public ResponseEntity updateDistributionSet(final Long distributionSetId, - final DistributionSetRequestBodyPut toUpdate) { + public ResponseEntity updateDistributionSet( + @PathVariable("distributionSetId") final Long distributionSetId, + @RequestBody final MgmtDistributionSetRequestBodyPut toUpdate) { final DistributionSet set = findDistributionSetWithExceptionIfNotFound(distributionSetId); if (toUpdate.getDescription() != null) { @@ -148,13 +158,17 @@ public class DistributionSetResource implements DistributionSetRestApi { set.setVersion(toUpdate.getVersion()); } return new ResponseEntity<>( - DistributionSetMapper.toResponse(this.distributionSetManagement.updateDistributionSet(set)), + MgmtDistributionSetMapper.toResponse(this.distributionSetManagement.updateDistributionSet(set)), HttpStatus.OK); } @Override - public ResponseEntity> getAssignedTargets(final Long distributionSetId, - final int pagingOffsetParam, final int pagingLimitParam, final String sortParam, final String rsqlParam) { + public ResponseEntity> getAssignedTargets( + @PathVariable("distributionSetId") final Long distributionSetId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { // check if distribution set exists otherwise throw exception // immediately @@ -167,19 +181,23 @@ public class DistributionSetResource implements DistributionSetRestApi { final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting); final Page targetsAssignedDS; if (rsqlParam != null) { - targetsAssignedDS = this.targetManagement.findTargetByAssignedDistributionSet(distributionSetId, - RSQLUtility.parse(rsqlParam, TargetFields.class), pageable); + targetsAssignedDS = this.targetManagement.findTargetByAssignedDistributionSet(distributionSetId, rsqlParam, + pageable); } else { targetsAssignedDS = this.targetManagement.findTargetByAssignedDistributionSet(distributionSetId, pageable); } - return new ResponseEntity<>(new PagedList<>(TargetMapper.toResponse(targetsAssignedDS.getContent()), + return new ResponseEntity<>(new PagedList<>(MgmtTargetMapper.toResponse(targetsAssignedDS.getContent()), targetsAssignedDS.getTotalElements()), HttpStatus.OK); } @Override - public ResponseEntity> getInstalledTargets(final Long distributionSetId, - final int pagingOffsetParam, final int pagingLimitParam, final String sortParam, final String rsqlParam) { + public ResponseEntity> getInstalledTargets( + @PathVariable("distributionSetId") final Long distributionSetId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { // check if distribution set exists otherwise throw exception // immediately findDistributionSetWithExceptionIfNotFound(distributionSetId); @@ -192,33 +210,40 @@ public class DistributionSetResource implements DistributionSetRestApi { final Page targetsInstalledDS; if (rsqlParam != null) { targetsInstalledDS = this.targetManagement.findTargetByInstalledDistributionSet(distributionSetId, - RSQLUtility.parse(rsqlParam, TargetFields.class), pageable); + rsqlParam, pageable); } else { targetsInstalledDS = this.targetManagement.findTargetByInstalledDistributionSet(distributionSetId, pageable); } - return new ResponseEntity<>(new PagedList(TargetMapper.toResponse(targetsInstalledDS.getContent()), - targetsInstalledDS.getTotalElements()), HttpStatus.OK); + return new ResponseEntity<>( + new PagedList(MgmtTargetMapper.toResponse(targetsInstalledDS.getContent()), + targetsInstalledDS.getTotalElements()), + HttpStatus.OK); } @Override - public ResponseEntity createAssignedTarget(final Long distributionSetId, - final List targetIds) { + public ResponseEntity createAssignedTarget( + @PathVariable("distributionSetId") final Long distributionSetId, + @RequestBody final List targetIds) { final DistributionSetAssignmentResult assignDistributionSet = this.deployManagament.assignDistributionSet( distributionSetId, targetIds.stream() .map(t -> new TargetWithActionType(t.getId(), - RestResourceConversionHelper.convertActionType(t.getType()), t.getForcetime())) + MgmtRestModelMapper.convertActionType(t.getType()), t.getForcetime())) .collect(Collectors.toList())); - return new ResponseEntity<>(DistributionSetMapper.toResponse(assignDistributionSet), HttpStatus.OK); + return new ResponseEntity<>(MgmtDistributionSetMapper.toResponse(assignDistributionSet), HttpStatus.OK); } @Override - public ResponseEntity> getMetadata(final Long distributionSetId, - final int pagingOffsetParam, final int pagingLimitParam, final String sortParam, final String rsqlParam) { + public ResponseEntity> getMetadata( + @PathVariable("distributionSetId") final Long distributionSetId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { // check if distribution set exists otherwise throw exception // immediately @@ -232,72 +257,75 @@ public class DistributionSetResource implements DistributionSetRestApi { final Page metaDataPage; if (rsqlParam != null) { - metaDataPage = this.distributionSetManagement.findDistributionSetMetadataByDistributionSetId( - distributionSetId, RSQLUtility.parse(rsqlParam, DistributionSetMetadataFields.class), pageable); + metaDataPage = this.distributionSetManagement + .findDistributionSetMetadataByDistributionSetId(distributionSetId, rsqlParam, pageable); } else { metaDataPage = this.distributionSetManagement .findDistributionSetMetadataByDistributionSetId(distributionSetId, pageable); } return new ResponseEntity<>( - new PagedList<>(DistributionSetMapper.toResponseDsMetadata(metaDataPage.getContent()), + new PagedList<>(MgmtDistributionSetMapper.toResponseDsMetadata(metaDataPage.getContent()), metaDataPage.getTotalElements()), HttpStatus.OK); } @Override - public ResponseEntity getMetadataValue(final Long distributionSetId, final String metadataKey) { + public ResponseEntity getMetadataValue( + @PathVariable("distributionSetId") final Long distributionSetId, + @PathVariable("metadataKey") final String metadataKey) { // check if distribution set exists otherwise throw exception // immediately final DistributionSet ds = findDistributionSetWithExceptionIfNotFound(distributionSetId); - final DistributionSetMetadata findOne = this.distributionSetManagement - .findOne(new DsMetadataCompositeKey(ds, metadataKey)); - return ResponseEntity. ok(DistributionSetMapper.toResponseDsMetadata(findOne)); + final DistributionSetMetadata findOne = this.distributionSetManagement.findOne(ds, metadataKey); + return ResponseEntity. ok(MgmtDistributionSetMapper.toResponseDsMetadata(findOne)); } @Override - public ResponseEntity updateMetadata(final Long distributionSetId, final String metadataKey, - final MetadataRest metadata) { + public ResponseEntity updateMetadata(@PathVariable("distributionSetId") final Long distributionSetId, + @PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadata metadata) { // check if distribution set exists otherwise throw exception // immediately final DistributionSet ds = findDistributionSetWithExceptionIfNotFound(distributionSetId); - final DistributionSetMetadata updated = this.distributionSetManagement - .updateDistributionSetMetadata(new DistributionSetMetadata(metadataKey, ds, metadata.getValue())); - return ResponseEntity.ok(DistributionSetMapper.toResponseDsMetadata(updated)); + final DistributionSetMetadata updated = this.distributionSetManagement.updateDistributionSetMetadata( + entityFactory.generateDistributionSetMetadata(ds, metadataKey, metadata.getValue())); + return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDsMetadata(updated)); } @Override - public ResponseEntity deleteMetadata(final Long distributionSetId, final String metadataKey) { + public ResponseEntity deleteMetadata(@PathVariable("distributionSetId") final Long distributionSetId, + @PathVariable("metadataKey") final String metadataKey) { // check if distribution set exists otherwise throw exception // immediately final DistributionSet ds = findDistributionSetWithExceptionIfNotFound(distributionSetId); - this.distributionSetManagement.deleteDistributionSetMetadata(new DsMetadataCompositeKey(ds, metadataKey)); + this.distributionSetManagement.deleteDistributionSetMetadata(ds, metadataKey); return ResponseEntity.ok().build(); } @Override - public ResponseEntity> createMetadata(final Long distributionSetId, - final List metadataRest) { + public ResponseEntity> createMetadata( + @PathVariable("distributionSetId") final Long distributionSetId, + @RequestBody final List metadataRest) { // check if distribution set exists otherwise throw exception // immediately final DistributionSet ds = findDistributionSetWithExceptionIfNotFound(distributionSetId); - final List created = this.distributionSetManagement - .createDistributionSetMetadata(DistributionSetMapper.fromRequestDsMetadata(ds, metadataRest)); - return new ResponseEntity<>(DistributionSetMapper.toResponseDsMetadata(created), HttpStatus.CREATED); + final List created = this.distributionSetManagement.createDistributionSetMetadata( + MgmtDistributionSetMapper.fromRequestDsMetadata(ds, metadataRest, entityFactory)); + return new ResponseEntity<>(MgmtDistributionSetMapper.toResponseDsMetadata(created), HttpStatus.CREATED); } @Override - public ResponseEntity assignSoftwareModules(final Long distributionSetId, - final List softwareModuleIDs) { + public ResponseEntity assignSoftwareModules(@PathVariable("distributionSetId") final Long distributionSetId, + @RequestBody final List softwareModuleIDs) { // check if distribution set exists otherwise throw exception // immediately final DistributionSet ds = findDistributionSetWithExceptionIfNotFound(distributionSetId); final Set softwareModuleToBeAssigned = new HashSet<>(); - for (final SoftwareModuleAssigmentRest sm : softwareModuleIDs) { + for (final MgmtSoftwareModuleAssigment sm : softwareModuleIDs) { final SoftwareModule softwareModule = this.softwareManagement.findSoftwareModuleById(sm.getId()); if (softwareModule != null) { softwareModuleToBeAssigned.add(softwareModule); @@ -311,7 +339,9 @@ public class DistributionSetResource implements DistributionSetRestApi { } @Override - public ResponseEntity deleteAssignSoftwareModules(final Long distributionSetId, final Long softwareModuleId) { + public ResponseEntity deleteAssignSoftwareModules( + @PathVariable("distributionSetId") final Long distributionSetId, + @PathVariable("softwareModuleId") final Long softwareModuleId) { // check if distribution set and software module exist otherwise throw // exception immediately final DistributionSet ds = findDistributionSetWithExceptionIfNotFound(distributionSetId); @@ -321,8 +351,11 @@ public class DistributionSetResource implements DistributionSetRestApi { } @Override - public ResponseEntity> getAssignedSoftwareModules(final Long distributionSetId, - final int pagingOffsetParam, final int pagingLimitParam, final String sortParam) { + public ResponseEntity> getAssignedSoftwareModules( + @PathVariable("distributionSetId") final Long distributionSetId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam) { // check if distribution set exists otherwise throw exception // immediately final DistributionSet foundDs = findDistributionSetWithExceptionIfNotFound(distributionSetId); @@ -332,7 +365,7 @@ public class DistributionSetResource implements DistributionSetRestApi { final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting); final Page softwaremodules = this.softwareManagement.findSoftwareModuleByAssignedTo(pageable, foundDs); - return new ResponseEntity<>(new PagedList<>(SoftwareModuleMapper.toResponse(softwaremodules.getContent()), + return new ResponseEntity<>(new PagedList<>(MgmtSoftwareModuleMapper.toResponse(softwaremodules.getContent()), softwaremodules.getTotalElements()), HttpStatus.OK); } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTagResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResource.java similarity index 56% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTagResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResource.java index eaa0fec28..18ec162ca 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTagResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResource.java @@ -6,26 +6,27 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import java.util.List; import java.util.stream.Collectors; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedDistributionSetRequestBody; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtDistributionSetTagAssigmentResult; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTagRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.DistributionSetManagement; -import org.eclipse.hawkbit.repository.TagFields; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.TagManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; -import org.eclipse.hawkbit.repository.rsql.RSQLUtility; -import org.eclipse.hawkbit.rest.resource.api.DistributionSetTagRestApi; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest; -import org.eclipse.hawkbit.rest.resource.model.tag.AssignedDistributionSetRequestBody; -import org.eclipse.hawkbit.rest.resource.model.tag.DistributionSetTagAssigmentResultRest; -import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.tag.TagRest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -35,6 +36,9 @@ import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** @@ -42,8 +46,8 @@ import org.springframework.web.bind.annotation.RestController; * */ @RestController -public class DistributionSetTagResource implements DistributionSetTagRestApi { - private static final Logger LOG = LoggerFactory.getLogger(DistributionSetTagResource.class); +public class MgmtDistributionSetTagResource implements MgmtDistributionSetTagRestApi { + private static final Logger LOG = LoggerFactory.getLogger(MgmtDistributionSetTagResource.class); @Autowired private TagManagement tagManagement; @@ -51,9 +55,15 @@ public class DistributionSetTagResource implements DistributionSetTagRestApi { @Autowired private DistributionSetManagement distributionSetManagement; + @Autowired + private EntityFactory entityFactory; + @Override - public ResponseEntity> getDistributionSetTags(final int pagingOffsetParam, - final int pagingLimitParam, final String sortParam, final String rsqlParam) { + public ResponseEntity> getDistributionSetTags( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -67,50 +77,54 @@ public class DistributionSetTagResource implements DistributionSetTagRestApi { countTargetsAll = this.tagManagement.countTargetTags(); } else { - final Page findTargetPage = this.tagManagement - .findAllDistributionSetTags(RSQLUtility.parse(rsqlParam, TagFields.class), pageable); + final Page findTargetPage = this.tagManagement.findAllDistributionSetTags(rsqlParam, + pageable); countTargetsAll = findTargetPage.getTotalElements(); findTargetsAll = findTargetPage; } - final List rest = TagMapper.toResponseDistributionSetTag(findTargetsAll.getContent()); + final List rest = MgmtTagMapper.toResponseDistributionSetTag(findTargetsAll.getContent()); return new ResponseEntity<>(new PagedList<>(rest, countTargetsAll), HttpStatus.OK); } @Override - public ResponseEntity getDistributionSetTag(final Long distributionsetTagId) { + public ResponseEntity getDistributionSetTag( + @PathVariable("distributionsetTagId") final Long distributionsetTagId) { final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); - return new ResponseEntity<>(TagMapper.toResponse(tag), HttpStatus.OK); + return new ResponseEntity<>(MgmtTagMapper.toResponse(tag), HttpStatus.OK); } @Override - public ResponseEntity> createDistributionSetTags(final List tags) { + public ResponseEntity> createDistributionSetTags( + @RequestBody final List tags) { LOG.debug("creating {} ds tags", tags.size()); final List createdTags = this.tagManagement - .createDistributionSetTags(TagMapper.mapDistributionSetTagFromRequest(tags)); + .createDistributionSetTags(MgmtTagMapper.mapDistributionSetTagFromRequest(entityFactory, tags)); - return new ResponseEntity<>(TagMapper.toResponseDistributionSetTag(createdTags), HttpStatus.CREATED); + return new ResponseEntity<>(MgmtTagMapper.toResponseDistributionSetTag(createdTags), HttpStatus.CREATED); } @Override - public ResponseEntity updateDistributionSetTag(final Long distributionsetTagId, - final TagRequestBodyPut restDSTagRest) { + public ResponseEntity updateDistributionSetTag( + @PathVariable("distributionsetTagId") final Long distributionsetTagId, + @RequestBody final MgmtTagRequestBodyPut restDSTagRest) { LOG.debug("update {} ds tag", restDSTagRest); final DistributionSetTag distributionSetTag = findDistributionTagById(distributionsetTagId); - TagMapper.updateTag(restDSTagRest, distributionSetTag); + MgmtTagMapper.updateTag(restDSTagRest, distributionSetTag); final DistributionSetTag updateDistributionSetTag = this.tagManagement .updateDistributionSetTag(distributionSetTag); LOG.debug("ds tag updated"); - return new ResponseEntity<>(TagMapper.toResponse(updateDistributionSetTag), HttpStatus.OK); + return new ResponseEntity<>(MgmtTagMapper.toResponse(updateDistributionSetTag), HttpStatus.OK); } @Override - public ResponseEntity deleteDistributionSetTag(final Long distributionsetTagId) { + public ResponseEntity deleteDistributionSetTag( + @PathVariable("distributionsetTagId") final Long distributionsetTagId) { LOG.debug("Delete {} distribution set tag", distributionsetTagId); final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); @@ -120,15 +134,18 @@ public class DistributionSetTagResource implements DistributionSetTagRestApi { } @Override - public ResponseEntity> getAssignedDistributionSets(final Long distributionsetTagId) { + public ResponseEntity> getAssignedDistributionSets( + @PathVariable("distributionsetTagId") final Long distributionsetTagId) { final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); return new ResponseEntity<>( - DistributionSetMapper.toResponseDistributionSets(tag.getAssignedToDistributionSet()), HttpStatus.OK); + MgmtDistributionSetMapper.toResponseDistributionSets(tag.getAssignedToDistributionSet()), + HttpStatus.OK); } @Override - public ResponseEntity toggleTagAssignment(final Long distributionsetTagId, - final List assignedDSRequestBodies) { + public ResponseEntity toggleTagAssignment( + @PathVariable("distributionsetTagId") final Long distributionsetTagId, + @RequestBody final List assignedDSRequestBodies) { LOG.debug("Toggle distribution set assignment {} for ds tag {}", assignedDSRequestBodies.size(), distributionsetTagId); @@ -137,11 +154,11 @@ public class DistributionSetTagResource implements DistributionSetTagRestApi { final DistributionSetTagAssignmentResult assigmentResult = this.distributionSetManagement .toggleTagAssignment(findDistributionSetIds(assignedDSRequestBodies), tag.getName()); - final DistributionSetTagAssigmentResultRest tagAssigmentResultRest = new DistributionSetTagAssigmentResultRest(); + final MgmtDistributionSetTagAssigmentResult tagAssigmentResultRest = new MgmtDistributionSetTagAssigmentResult(); tagAssigmentResultRest.setAssignedDistributionSets( - DistributionSetMapper.toResponseDistributionSets(assigmentResult.getAssignedEntity())); + MgmtDistributionSetMapper.toResponseDistributionSets(assigmentResult.getAssignedEntity())); tagAssigmentResultRest.setUnassignedDistributionSets( - DistributionSetMapper.toResponseDistributionSets(assigmentResult.getUnassignedEntity())); + MgmtDistributionSetMapper.toResponseDistributionSets(assigmentResult.getUnassignedEntity())); LOG.debug("Toggled assignedDS {} and unassignedDS{}", assigmentResult.getAssigned(), assigmentResult.getUnassigned()); @@ -150,19 +167,21 @@ public class DistributionSetTagResource implements DistributionSetTagRestApi { } @Override - public ResponseEntity> assignDistributionSets(final Long distributionsetTagId, - final List assignedDSRequestBodies) { + public ResponseEntity> assignDistributionSets( + @PathVariable("distributionsetTagId") final Long distributionsetTagId, + @RequestBody final List assignedDSRequestBodies) { LOG.debug("Assign DistributionSet {} for ds tag {}", assignedDSRequestBodies.size(), distributionsetTagId); final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); final List assignedDs = this.distributionSetManagement .assignTag(findDistributionSetIds(assignedDSRequestBodies), tag); LOG.debug("Assignd DistributionSet {}", assignedDs.size()); - return new ResponseEntity<>(DistributionSetMapper.toResponseDistributionSets(assignedDs), HttpStatus.OK); + return new ResponseEntity<>(MgmtDistributionSetMapper.toResponseDistributionSets(assignedDs), HttpStatus.OK); } @Override - public ResponseEntity unassignDistributionSets(final Long distributionsetTagId) { + public ResponseEntity unassignDistributionSets( + @PathVariable("distributionsetTagId") final Long distributionsetTagId) { LOG.debug("Unassign all DS for ds tag {}", distributionsetTagId); final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); if (tag.getAssignedToDistributionSet() == null) { @@ -177,7 +196,9 @@ public class DistributionSetTagResource implements DistributionSetTagRestApi { } @Override - public ResponseEntity unassignDistributionSet(final Long distributionsetTagId, final Long distributionsetId) { + public ResponseEntity unassignDistributionSet( + @PathVariable("distributionsetTagId") final Long distributionsetTagId, + @PathVariable("distributionsetId") final Long distributionsetId) { LOG.debug("Unassign ds {} for ds tag {}", distributionsetId, distributionsetTagId); final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); this.distributionSetManagement.unAssignTag(distributionsetId, tag); @@ -193,7 +214,7 @@ public class DistributionSetTagResource implements DistributionSetTagRestApi { } private List findDistributionSetIds( - final List assignedDistributionSetRequestBodies) { + final List assignedDistributionSetRequestBodies) { return assignedDistributionSetRequestBodies.stream().map(request -> request.getDistributionSetId()) .collect(Collectors.toList()); } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeMapper.java similarity index 52% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeMapper.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeMapper.java index 409caf01d..5c139027c 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeMapper.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeMapper.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; @@ -14,41 +14,44 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; import java.util.ArrayList; import java.util.List; +import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType; +import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.rest.resource.api.DistributionSetTypeRestApi; -import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRest; /** * A mapper which maps repository model to RESTful model representation and * back. * */ -final class DistributionSetTypeMapper { +final class MgmtDistributionSetTypeMapper { // private constructor, utility class - private DistributionSetTypeMapper() { + private MgmtDistributionSetTypeMapper() { } - static List smFromRequest(final SoftwareManagement softwareManagement, - final Iterable smTypesRest) { + static List smFromRequest(final EntityFactory entityFactory, + final SoftwareManagement softwareManagement, + final Iterable smTypesRest) { final List mappedList = new ArrayList<>(); - for (final DistributionSetTypeRequestBodyPost smRest : smTypesRest) { - mappedList.add(fromRequest(softwareManagement, smRest)); + for (final MgmtDistributionSetTypeRequestBodyPost smRest : smTypesRest) { + mappedList.add(fromRequest(entityFactory, softwareManagement, smRest)); } return mappedList; } - static DistributionSetType fromRequest(final SoftwareManagement softwareManagement, - final DistributionSetTypeRequestBodyPost smsRest) { + static DistributionSetType fromRequest(final EntityFactory entityFactory, + final SoftwareManagement softwareManagement, final MgmtDistributionSetTypeRequestBodyPost smsRest) { - final DistributionSetType result = new DistributionSetType(smsRest.getKey(), smsRest.getName(), - smsRest.getDescription()); + final DistributionSetType result = entityFactory.generateDistributionSetType(smsRest.getKey(), + smsRest.getName(), smsRest.getDescription()); // Add mandatory smsRest.getMandatorymodules().stream().map(mand -> { @@ -75,37 +78,37 @@ final class DistributionSetTypeMapper { return result; } - static List toTypesResponse(final List types) { - final List response = new ArrayList<>(); + static List toTypesResponse(final List types) { + final List response = new ArrayList<>(); for (final DistributionSetType dsType : types) { response.add(toResponse(dsType)); } return response; } - static List toListResponse(final List types) { - final List response = new ArrayList<>(); + static List toListResponse(final List types) { + final List response = new ArrayList<>(); for (final DistributionSetType dsType : types) { response.add(toResponse(dsType)); } return response; } - static DistributionSetTypeRest toResponse(final DistributionSetType type) { - final DistributionSetTypeRest result = new DistributionSetTypeRest(); + static MgmtDistributionSetType toResponse(final DistributionSetType type) { + final MgmtDistributionSetType result = new MgmtDistributionSetType(); - RestModelMapper.mapNamedToNamed(result, type); + MgmtRestModelMapper.mapNamedToNamed(result, type); result.setKey(type.getKey()); result.setModuleId(type.getId()); - result.add(linkTo(methodOn(DistributionSetTypeRestApi.class).getDistributionSetType(result.getModuleId())) + result.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class).getDistributionSetType(result.getModuleId())) .withRel("self")); - result.add(linkTo(methodOn(DistributionSetTypeRestApi.class).getMandatoryModules(result.getModuleId())) - .withRel(RestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULES)); + result.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class).getMandatoryModules(result.getModuleId())) + .withRel(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULES)); - result.add(linkTo(methodOn(DistributionSetTypeRestApi.class).getOptionalModules(result.getModuleId())) - .withRel(RestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULES)); + result.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class).getOptionalModules(result.getModuleId())) + .withRel(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULES)); return result; } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResource.java similarity index 62% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResource.java index f7346a6ff..d69e4d8d4 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResource.java @@ -6,26 +6,27 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import java.util.List; +import org.eclipse.hawkbit.mgmt.json.model.MgmtId; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType; +import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPut; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.DistributionSetManagement; -import org.eclipse.hawkbit.repository.DistributionSetTypeFields; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.rsql.RSQLUtility; -import org.eclipse.hawkbit.rest.resource.api.DistributionSetTypeRestApi; -import org.eclipse.hawkbit.rest.resource.model.IdRest; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRest; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -45,7 +46,7 @@ import org.springframework.web.bind.annotation.RestController; * */ @RestController -public class DistributionSetTypeResource implements DistributionSetTypeRestApi { +public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeRestApi { @Autowired private SoftwareManagement softwareManagement; @@ -53,12 +54,15 @@ public class DistributionSetTypeResource implements DistributionSetTypeRestApi { @Autowired private DistributionSetManagement distributionSetManagement; + @Autowired + private EntityFactory entityFactory; + @Override - public ResponseEntity> getDistributionSetTypes( - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { + public ResponseEntity> getDistributionSetTypes( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -69,29 +73,29 @@ public class DistributionSetTypeResource implements DistributionSetTypeRestApi { final Slice findModuleTypessAll; Long countModulesAll; if (rsqlParam != null) { - findModuleTypessAll = distributionSetManagement.findDistributionSetTypesByPredicate( - RSQLUtility.parse(rsqlParam, DistributionSetTypeFields.class), pageable); + findModuleTypessAll = distributionSetManagement.findDistributionSetTypesAll(rsqlParam, pageable); countModulesAll = ((Page) findModuleTypessAll).getTotalElements(); } else { findModuleTypessAll = distributionSetManagement.findDistributionSetTypesAll(pageable); countModulesAll = distributionSetManagement.countDistributionSetTypesAll(); } - final List rest = DistributionSetTypeMapper + final List rest = MgmtDistributionSetTypeMapper .toListResponse(findModuleTypessAll.getContent()); return new ResponseEntity<>(new PagedList<>(rest, countModulesAll), HttpStatus.OK); } @Override - public ResponseEntity getDistributionSetType( - @PathVariable final Long distributionSetTypeId) { + public ResponseEntity getDistributionSetType( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); - return new ResponseEntity<>(DistributionSetTypeMapper.toResponse(foundType), HttpStatus.OK); + return new ResponseEntity<>(MgmtDistributionSetTypeMapper.toResponse(foundType), HttpStatus.OK); } @Override - public ResponseEntity deleteDistributionSetType(@PathVariable final Long distributionSetTypeId) { + public ResponseEntity deleteDistributionSetType( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId) { final DistributionSetType module = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); distributionSetManagement.deleteDistributionSetType(module); @@ -100,9 +104,9 @@ public class DistributionSetTypeResource implements DistributionSetTypeRestApi { } @Override - public ResponseEntity updateDistributionSetType( - @PathVariable final Long distributionSetTypeId, - @RequestBody final DistributionSetTypeRequestBodyPut restDistributionSetType) { + public ResponseEntity updateDistributionSetType( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @RequestBody final MgmtDistributionSetTypeRequestBodyPut restDistributionSetType) { final DistributionSetType type = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); // only description can be modified @@ -113,17 +117,18 @@ public class DistributionSetTypeResource implements DistributionSetTypeRestApi { final DistributionSetType updatedDistributionSetType = distributionSetManagement .updateDistributionSetType(type); - return new ResponseEntity<>(DistributionSetTypeMapper.toResponse(updatedDistributionSetType), HttpStatus.OK); + return new ResponseEntity<>(MgmtDistributionSetTypeMapper.toResponse(updatedDistributionSetType), + HttpStatus.OK); } @Override - public ResponseEntity> createDistributionSetTypes( - @RequestBody final List distributionSetTypes) { + public ResponseEntity> createDistributionSetTypes( + @RequestBody final List distributionSetTypes) { final List createdSoftwareModules = distributionSetManagement.createDistributionSetTypes( - DistributionSetTypeMapper.smFromRequest(softwareManagement, distributionSetTypes)); + MgmtDistributionSetTypeMapper.smFromRequest(entityFactory, softwareManagement, distributionSetTypes)); - return new ResponseEntity<>(DistributionSetTypeMapper.toTypesResponse(createdSoftwareModules), + return new ResponseEntity<>(MgmtDistributionSetTypeMapper.toTypesResponse(createdSoftwareModules), HttpStatus.CREATED); } @@ -137,17 +142,18 @@ public class DistributionSetTypeResource implements DistributionSetTypeRestApi { } @Override - public ResponseEntity> getMandatoryModules( - @PathVariable final Long distributionSetTypeId) { + public ResponseEntity> getMandatoryModules( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); - return new ResponseEntity<>(SoftwareModuleTypeMapper.toListResponse(foundType.getMandatoryModuleTypes()), + return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toListResponse(foundType.getMandatoryModuleTypes()), HttpStatus.OK); } @Override - public ResponseEntity getMandatoryModule(@PathVariable final Long distributionSetTypeId, - @PathVariable final Long softwareModuleTypeId) { + public ResponseEntity getMandatoryModule( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); @@ -158,12 +164,13 @@ public class DistributionSetTypeResource implements DistributionSetTypeRestApi { "Software module with given ID is not part of this distribution set type!"); } - return new ResponseEntity<>(SoftwareModuleTypeMapper.toResponse(foundSmType), HttpStatus.OK); + return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toResponse(foundSmType), HttpStatus.OK); } @Override - public ResponseEntity getOptionalModule(@PathVariable final Long distributionSetTypeId, - @PathVariable final Long softwareModuleTypeId) { + public ResponseEntity getOptionalModule( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); @@ -174,22 +181,23 @@ public class DistributionSetTypeResource implements DistributionSetTypeRestApi { "Software module with given ID is not part of this distribution set type!"); } - return new ResponseEntity<>(SoftwareModuleTypeMapper.toResponse(foundSmType), HttpStatus.OK); + return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toResponse(foundSmType), HttpStatus.OK); } @Override - public ResponseEntity> getOptionalModules( - @PathVariable final Long distributionSetTypeId) { + public ResponseEntity> getOptionalModules( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); - return new ResponseEntity<>(SoftwareModuleTypeMapper.toListResponse(foundType.getOptionalModuleTypes()), + return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toListResponse(foundType.getOptionalModuleTypes()), HttpStatus.OK); } @Override - public ResponseEntity removeMandatoryModule(@PathVariable final Long distributionSetTypeId, - @PathVariable final Long softwareModuleTypeId) { + public ResponseEntity removeMandatoryModule( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); @@ -208,8 +216,9 @@ public class DistributionSetTypeResource implements DistributionSetTypeRestApi { } @Override - public ResponseEntity removeOptionalModule(@PathVariable final Long distributionSetTypeId, - @PathVariable final Long softwareModuleTypeId) { + public ResponseEntity removeOptionalModule( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); final SoftwareModuleType foundSmType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId); @@ -227,8 +236,8 @@ public class DistributionSetTypeResource implements DistributionSetTypeRestApi { } @Override - public ResponseEntity addMandatoryModule(@PathVariable final Long distributionSetTypeId, - @RequestBody final IdRest smtId) { + public ResponseEntity addMandatoryModule( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @RequestBody final MgmtId smtId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); @@ -242,8 +251,8 @@ public class DistributionSetTypeResource implements DistributionSetTypeRestApi { } @Override - public ResponseEntity addOptionalModule(@PathVariable final Long distributionSetTypeId, - @RequestBody final IdRest smtId) { + public ResponseEntity addOptionalModule( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @RequestBody final MgmtId smtId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DownloadArtifactResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadArtifactResource.java similarity index 74% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DownloadArtifactResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadArtifactResource.java index 00f8f4756..dad43bf00 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DownloadArtifactResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadArtifactResource.java @@ -6,34 +6,36 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; + +import java.io.InputStream; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadArtifactRestApi; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper; +import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder; +import org.eclipse.hawkbit.rest.util.RestResourceConversionHelper; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.WebApplicationContext; /** - * @author Jonathan Knoblauch * */ @RestController -@RequestMapping(RestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) -public class DownloadArtifactResource { +@Scope(value = WebApplicationContext.SCOPE_REQUEST) +public class MgmtDownloadArtifactResource implements MgmtDownloadArtifactRestApi { @Autowired private SoftwareManagement softwareManagement; @@ -41,6 +43,9 @@ public class DownloadArtifactResource { @Autowired private ArtifactManagement artifactManagement; + @Autowired + private RequestResponseContextHolder requestResponseContextHolder; + /** * Handles the GET request for downloading an artifact. * @@ -48,18 +53,13 @@ public class DownloadArtifactResource { * of the parent SoftwareModule * @param artifactId * of the related LocalArtifact - * @param servletResponse - * of the servlet - * @param request - * of the client * * @return responseEntity with status ok if successful */ - @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/artifacts/{artifactId}/download") + @Override @ResponseBody - public ResponseEntity downloadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, - @PathVariable("artifactId") final Long artifactId, final HttpServletResponse servletResponse, - final HttpServletRequest request) { + public ResponseEntity downloadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("artifactId") final Long artifactId) { final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId); if (null == module || !module.getLocalArtifact(artifactId).isPresent()) { @@ -68,13 +68,14 @@ public class DownloadArtifactResource { final LocalArtifact artifact = module.getLocalArtifact(artifactId).get(); final DbArtifact file = artifactManagement.loadLocalArtifactBinary(artifact); - + final HttpServletRequest request = requestResponseContextHolder.getHttpServletRequest(); final String ifMatch = request.getHeader("If-Match"); if (ifMatch != null && !RestResourceConversionHelper.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) { return new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED); } - return RestResourceConversionHelper.writeFileResponse(artifact, servletResponse, request, file); + return RestResourceConversionHelper.writeFileResponse(artifact, + requestResponseContextHolder.getHttpServletResponse(), request, file); } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DownloadResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResource.java similarity index 81% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DownloadResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResource.java index 14b1dcbc6..87a215183 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DownloadResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResource.java @@ -6,30 +6,30 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import java.io.IOException; -import javax.servlet.http.HttpServletResponse; - import org.apache.commons.io.IOUtils; import org.eclipse.hawkbit.artifact.repository.ArtifactRepository; import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; import org.eclipse.hawkbit.cache.CacheConstants; import org.eclipse.hawkbit.cache.DownloadArtifactCache; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadRestApi; +import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.cache.Cache; import org.springframework.cache.Cache.ValueWrapper; +import org.springframework.context.annotation.Scope; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.WebApplicationContext; /** * A resource for download artifacts. @@ -37,11 +37,11 @@ import org.springframework.web.bind.annotation.RestController; * * */ -@RequestMapping(RestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE) @RestController -public class DownloadResource { +@Scope(value = WebApplicationContext.SCOPE_REQUEST) +public class MgmtDownloadResource implements MgmtDownloadRestApi { - private static final Logger LOGGER = LoggerFactory.getLogger(DownloadResource.class); + private static final Logger LOGGER = LoggerFactory.getLogger(MgmtDownloadResource.class); @Autowired private ArtifactRepository artifactRepository; @@ -50,20 +50,20 @@ public class DownloadResource { @Qualifier(CacheConstants.DOWNLOAD_ID_CACHE) private Cache cache; + @Autowired + private RequestResponseContextHolder requestResponseContextHolder; + /** * Handles the GET request for downloading an artifact. * * @param downloadId * the generated download id - * @param response - * of the servlet * @return {@link ResponseEntity} with status {@link HttpStatus#OK} if * successful */ - @RequestMapping(method = RequestMethod.GET, value = RestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING) + @Override @ResponseBody - public ResponseEntity downloadArtifactByDownloadId(@PathVariable final String downloadId, - final HttpServletResponse response) { + public ResponseEntity downloadArtifactByDownloadId(@PathVariable("downloadId") final String downloadId) { try { final ValueWrapper cacheWrapper = cache.get(downloadId); if (cacheWrapper == null) { @@ -89,7 +89,8 @@ public class DownloadResource { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } try { - IOUtils.copy(artifact.getFileInputStream(), response.getOutputStream()); + IOUtils.copy(artifact.getFileInputStream(), + requestResponseContextHolder.getHttpServletResponse().getOutputStream()); } catch (final IOException e) { LOGGER.error("Cannot copy streams", e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRestModelMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRestModelMapper.java new file mode 100644 index 000000000..deee0e461 --- /dev/null +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRestModelMapper.java @@ -0,0 +1,81 @@ +/** + * 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.mgmt.rest.resource; + +import org.eclipse.hawkbit.mgmt.json.model.MgmtBaseEntity; +import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType; +import org.eclipse.hawkbit.repository.model.Action.ActionType; +import org.eclipse.hawkbit.repository.model.NamedEntity; +import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; + +/** + * A mapper which maps repository model to RESTful model representation and + * back. + * + * + * + * + */ +final class MgmtRestModelMapper { + + // private constructor, utility class + private MgmtRestModelMapper() { + + } + + static void mapBaseToBase(final MgmtBaseEntity response, final TenantAwareBaseEntity base) { + response.setCreatedBy(base.getCreatedBy()); + response.setLastModifiedBy(base.getLastModifiedBy()); + if (base.getCreatedAt() != null) { + response.setCreatedAt(base.getCreatedAt()); + } + if (base.getLastModifiedAt() != null) { + response.setLastModifiedAt(base.getLastModifiedAt()); + } + } + + static void mapNamedToNamed(final MgmtNamedEntity response, final NamedEntity base) { + mapBaseToBase(response, base); + + response.setName(base.getName()); + response.setDescription(base.getDescription()); + } + + /** + * Convert a action rest type to a action repository type. + * + * @param actionTypeRest + * the rest type + * @return or the action repository type + */ + /** + * Convert a action rest type to a action repository type. + * + * @param actionTypeRest + * the rest type + * @return or the action repository type + */ + public static ActionType convertActionType(final MgmtActionType actionTypeRest) { + if (actionTypeRest == null) { + return null; + } + + switch (actionTypeRest) { + case SOFT: + return ActionType.SOFT; + case FORCED: + return ActionType.FORCED; + case TIMEFORCED: + return ActionType.TIMEFORCED; + default: + throw new IllegalStateException("Action Type is not supported"); + } + } +} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutMapper.java similarity index 65% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutMapper.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutMapper.java index c6be219ba..7467a45b0 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutMapper.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutMapper.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; @@ -14,6 +14,15 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; import java.util.ArrayList; import java.util.List; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition.Condition; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutErrorAction.ErrorAction; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBody; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutSuccessAction.SuccessAction; +import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroupResponseBody; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi; +import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Rollout; @@ -23,14 +32,6 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondit import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessAction; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; -import org.eclipse.hawkbit.rest.resource.api.RolloutRestApi; -import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutCondition.Condition; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutErrorAction.ErrorAction; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutResponseBody; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutRestRequestBody; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutSuccessAction.SuccessAction; -import org.eclipse.hawkbit.rest.resource.model.rolloutgroup.RolloutGroupResponseBody; /** * A mapper which maps repository model to RESTful model representation and @@ -38,22 +39,22 @@ import org.eclipse.hawkbit.rest.resource.model.rolloutgroup.RolloutGroupResponse * * */ -final class RolloutMapper { +final class MgmtRolloutMapper { private static final String NOT_SUPPORTED = " is not supported"; - private RolloutMapper() { + private MgmtRolloutMapper() { // Utility class } - static List toResponseRollout(final List rollouts) { - final List result = new ArrayList<>(rollouts.size()); + static List toResponseRollout(final List rollouts) { + final List result = new ArrayList<>(rollouts.size()); rollouts.forEach(r -> result.add(toResponseRollout(r))); return result; } - static RolloutResponseBody toResponseRollout(final Rollout rollout) { - final RolloutResponseBody body = new RolloutResponseBody(); + static MgmtRolloutResponseBody toResponseRollout(final Rollout rollout) { + final MgmtRolloutResponseBody body = new MgmtRolloutResponseBody(); body.setCreatedAt(rollout.getCreatedAt()); body.setCreatedBy(rollout.getCreatedBy()); body.setDescription(rollout.getDescription()); @@ -71,25 +72,26 @@ final class RolloutMapper { rollout.getTotalTargetCountStatus().getTotalTargetCountByStatus(status)); } - body.add(linkTo(methodOn(RolloutRestApi.class).getRollout(rollout.getId())).withRel("self")); - body.add(linkTo(methodOn(RolloutRestApi.class).start(rollout.getId(), false)).withRel("start")); - body.add(linkTo(methodOn(RolloutRestApi.class).start(rollout.getId(), true)).withRel("startAsync")); - body.add(linkTo(methodOn(RolloutRestApi.class).pause(rollout.getId())).withRel("pause")); - body.add(linkTo(methodOn(RolloutRestApi.class).resume(rollout.getId())).withRel("resume")); - body.add(linkTo(methodOn(RolloutRestApi.class).getRolloutGroups(rollout.getId(), - Integer.parseInt(RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET), - Integer.parseInt(RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT), null, null)).withRel("groups")); + body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRollout(rollout.getId())).withRel("self")); + body.add(linkTo(methodOn(MgmtRolloutRestApi.class).start(rollout.getId(), false)).withRel("start")); + body.add(linkTo(methodOn(MgmtRolloutRestApi.class).start(rollout.getId(), true)).withRel("startAsync")); + body.add(linkTo(methodOn(MgmtRolloutRestApi.class).pause(rollout.getId())).withRel("pause")); + body.add(linkTo(methodOn(MgmtRolloutRestApi.class).resume(rollout.getId())).withRel("resume")); + body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRolloutGroups(rollout.getId(), + Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET), + Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT), null, null)) + .withRel("groups")); return body; } - static Rollout fromRequest(final RolloutRestRequestBody restRequest, final DistributionSet distributionSet, - final String filterQuery) { - final Rollout rollout = new Rollout(); + static Rollout fromRequest(final EntityFactory entityFactory, final MgmtRolloutRestRequestBody restRequest, + final DistributionSet distributionSet, final String filterQuery) { + final Rollout rollout = entityFactory.generateRollout(); rollout.setName(restRequest.getName()); rollout.setDescription(restRequest.getDescription()); rollout.setDistributionSet(distributionSet); rollout.setTargetFilterQuery(filterQuery); - final ActionType convertActionType = RestResourceConversionHelper.convertActionType(restRequest.getType()); + final ActionType convertActionType = MgmtRestModelMapper.convertActionType(restRequest.getType()); if (convertActionType != null) { rollout.setActionType(convertActionType); } @@ -100,14 +102,14 @@ final class RolloutMapper { return rollout; } - static List toResponseRolloutGroup(final List rollouts) { - final List result = new ArrayList<>(rollouts.size()); + static List toResponseRolloutGroup(final List rollouts) { + final List result = new ArrayList<>(rollouts.size()); rollouts.forEach(r -> result.add(toResponseRolloutGroup(r))); return result; } - static RolloutGroupResponseBody toResponseRolloutGroup(final RolloutGroup rolloutGroup) { - final RolloutGroupResponseBody body = new RolloutGroupResponseBody(); + static MgmtRolloutGroupResponseBody toResponseRolloutGroup(final RolloutGroup rolloutGroup) { + final MgmtRolloutGroupResponseBody body = new MgmtRolloutGroupResponseBody(); body.setCreatedAt(rolloutGroup.getCreatedAt()); body.setCreatedBy(rolloutGroup.getCreatedBy()); body.setDescription(rolloutGroup.getDescription()); @@ -116,9 +118,8 @@ final class RolloutMapper { body.setName(rolloutGroup.getName()); body.setRolloutGroupId(rolloutGroup.getId()); body.setStatus(rolloutGroup.getStatus().toString().toLowerCase()); - body.add(linkTo( - methodOn(RolloutRestApi.class).getRolloutGroup(rolloutGroup.getRollout().getId(), rolloutGroup.getId())) - .withRel("self")); + body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRolloutGroup(rolloutGroup.getRollout().getId(), + rolloutGroup.getId())).withRel("self")); return body; } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResource.java similarity index 60% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResource.java index 78cfefa0d..7144316b8 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResource.java @@ -6,41 +6,43 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import java.util.List; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody; +import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBody; +import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroupResponseBody; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi; import org.eclipse.hawkbit.repository.DistributionSetManagement; -import org.eclipse.hawkbit.repository.RolloutFields; -import org.eclipse.hawkbit.repository.RolloutGroupFields; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.RolloutGroupManagement; import org.eclipse.hawkbit.repository.RolloutManagement; -import org.eclipse.hawkbit.repository.TargetFields; +import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessAction; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.rsql.RSQLUtility; -import org.eclipse.hawkbit.rest.resource.api.RolloutRestApi; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutResponseBody; -import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutRestRequestBody; -import org.eclipse.hawkbit.rest.resource.model.rolloutgroup.RolloutGroupResponseBody; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import org.springframework.data.jpa.domain.Specification; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** @@ -48,7 +50,7 @@ import org.springframework.web.bind.annotation.RestController; * */ @RestController -public class RolloutResource implements RolloutRestApi { +public class MgmtRolloutResource implements MgmtRolloutRestApi { private static final String DOES_NOT_EXIST = "} does not exist"; @@ -61,9 +63,18 @@ public class RolloutResource implements RolloutRestApi { @Autowired private DistributionSetManagement distributionSetManagement; + @Autowired + private TargetFilterQueryManagement targetFilterQueryManagement; + + @Autowired + private EntityFactory entityFactory; + @Override - public ResponseEntity> getRollouts(final int pagingOffsetParam, - final int pagingLimitParam, final String sortParam, final String rsqlParam) { + public ResponseEntity> getRollouts( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -73,28 +84,28 @@ public class RolloutResource implements RolloutRestApi { final Page findModulesAll; if (rsqlParam != null) { - findModulesAll = this.rolloutManagement - .findAllWithDetailedStatusByPredicate(RSQLUtility.parse(rsqlParam, RolloutFields.class), pageable); + findModulesAll = this.rolloutManagement.findAllWithDetailedStatusByPredicate(rsqlParam, pageable); } else { findModulesAll = this.rolloutManagement.findAll(pageable); } - final List rest = RolloutMapper.toResponseRollout(findModulesAll.getContent()); + final List rest = MgmtRolloutMapper.toResponseRollout(findModulesAll.getContent()); return new ResponseEntity<>(new PagedList<>(rest, findModulesAll.getTotalElements()), HttpStatus.OK); } @Override - public ResponseEntity getRollout(final Long rolloutId) { + public ResponseEntity getRollout(@PathVariable("rolloutId") final Long rolloutId) { final Rollout findRolloutById = findRolloutOrThrowException(rolloutId); - return new ResponseEntity<>(RolloutMapper.toResponseRollout(findRolloutById), HttpStatus.OK); + return new ResponseEntity<>(MgmtRolloutMapper.toResponseRollout(findRolloutById), HttpStatus.OK); } @Override - public ResponseEntity create(@RequestBody final RolloutRestRequestBody rolloutRequestBody) { + public ResponseEntity create( + @RequestBody final MgmtRolloutRestRequestBody rolloutRequestBody) { // first check the given RSQL query if it's well formed, otherwise and // exception is thrown - RSQLUtility.parse(rolloutRequestBody.getTargetFilterQuery(), TargetFields.class); + targetFilterQueryManagement.verifyTargetFilterQuerySyntax(rolloutRequestBody.getTargetFilterQuery()); final DistributionSet distributionSet = findDistributionSetOrThrowException(rolloutRequestBody); @@ -111,37 +122,38 @@ public class RolloutResource implements RolloutRestApi { RolloutGroupErrorAction errorAction = null; String errorActionExpr = null; if (rolloutRequestBody.getSuccessCondition() != null) { - successCondition = RolloutMapper + successCondition = MgmtRolloutMapper .mapFinishCondition(rolloutRequestBody.getSuccessCondition().getCondition()); successConditionExpr = rolloutRequestBody.getSuccessCondition().getExpression(); } if (rolloutRequestBody.getSuccessAction() != null) { - successAction = RolloutMapper.map(rolloutRequestBody.getSuccessAction().getAction()); + successAction = MgmtRolloutMapper.map(rolloutRequestBody.getSuccessAction().getAction()); successActionExpr = rolloutRequestBody.getSuccessAction().getExpression(); } if (rolloutRequestBody.getErrorCondition() != null) { - errorCondition = RolloutMapper.mapErrorCondition(rolloutRequestBody.getErrorCondition().getCondition()); + errorCondition = MgmtRolloutMapper.mapErrorCondition(rolloutRequestBody.getErrorCondition().getCondition()); errorConditionExpr = rolloutRequestBody.getErrorCondition().getExpression(); } if (rolloutRequestBody.getErrorAction() != null) { - errorAction = RolloutMapper.map(rolloutRequestBody.getErrorAction().getAction()); + errorAction = MgmtRolloutMapper.map(rolloutRequestBody.getErrorAction().getAction()); errorActionExpr = rolloutRequestBody.getErrorAction().getExpression(); } - final RolloutGroupConditions rolloutGroupConditions = new RolloutGroup.RolloutGroupConditionBuilder() + final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder() .successCondition(successCondition, successConditionExpr) .successAction(successAction, successActionExpr).errorCondition(errorCondition, errorConditionExpr) .errorAction(errorAction, errorActionExpr).build(); final Rollout rollout = this.rolloutManagement.createRollout( - RolloutMapper.fromRequest(rolloutRequestBody, distributionSet, + MgmtRolloutMapper.fromRequest(entityFactory, rolloutRequestBody, distributionSet, rolloutRequestBody.getTargetFilterQuery()), rolloutRequestBody.getAmountGroups(), rolloutGroupConditions); - return ResponseEntity.status(HttpStatus.CREATED).body(RolloutMapper.toResponseRollout(rollout)); + return ResponseEntity.status(HttpStatus.CREATED).body(MgmtRolloutMapper.toResponseRollout(rollout)); } @Override - public ResponseEntity start(final Long rolloutId, final boolean startAsync) { + public ResponseEntity start(@PathVariable("rolloutId") final Long rolloutId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_ASYNC, defaultValue = "false") final boolean startAsync) { final Rollout rollout = findRolloutOrThrowException(rolloutId); if (startAsync) { this.rolloutManagement.startRolloutAsync(rollout); @@ -152,22 +164,26 @@ public class RolloutResource implements RolloutRestApi { } @Override - public ResponseEntity pause(final Long rolloutId) { + public ResponseEntity pause(@PathVariable("rolloutId") final Long rolloutId) { final Rollout rollout = findRolloutOrThrowException(rolloutId); this.rolloutManagement.pauseRollout(rollout); return ResponseEntity.ok().build(); } @Override - public ResponseEntity resume(final Long rolloutId) { + public ResponseEntity resume(@PathVariable("rolloutId") final Long rolloutId) { final Rollout rollout = findRolloutOrThrowException(rolloutId); this.rolloutManagement.resumeRollout(rollout); return ResponseEntity.ok().build(); } @Override - public ResponseEntity> getRolloutGroups(final Long rolloutId, - final int pagingOffsetParam, final int pagingLimitParam, final String sortParam, final String rsqlParam) { + public ResponseEntity> getRolloutGroups( + @PathVariable("rolloutId") final Long rolloutId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { final Rollout rollout = findRolloutOrThrowException(rolloutId); final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); @@ -178,27 +194,31 @@ public class RolloutResource implements RolloutRestApi { final Page findRolloutGroupsAll; if (rsqlParam != null) { - findRolloutGroupsAll = this.rolloutGroupManagement.findRolloutGroupsByPredicate(rollout, - RSQLUtility.parse(rsqlParam, RolloutGroupFields.class), pageable); + findRolloutGroupsAll = this.rolloutGroupManagement.findRolloutGroupsAll(rollout, rsqlParam, pageable); } else { findRolloutGroupsAll = this.rolloutGroupManagement.findRolloutGroupsByRolloutId(rolloutId, pageable); } - final List rest = RolloutMapper + final List rest = MgmtRolloutMapper .toResponseRolloutGroup(findRolloutGroupsAll.getContent()); return new ResponseEntity<>(new PagedList<>(rest, findRolloutGroupsAll.getTotalElements()), HttpStatus.OK); } @Override - public ResponseEntity getRolloutGroup(final Long rolloutId, final Long groupId) { + public ResponseEntity getRolloutGroup(@PathVariable("rolloutId") final Long rolloutId, + @PathVariable("groupId") final Long groupId) { findRolloutOrThrowException(rolloutId); final RolloutGroup rolloutGroup = findRolloutGroupOrThrowException(groupId); - return ResponseEntity.ok(RolloutMapper.toResponseRolloutGroup(rolloutGroup)); + return ResponseEntity.ok(MgmtRolloutMapper.toResponseRolloutGroup(rolloutGroup)); } @Override - public ResponseEntity> getRolloutGroupTargets(final Long rolloutId, final Long groupId, - final int pagingOffsetParam, final int pagingLimitParam, final String sortParam, final String rsqlParam) { + public ResponseEntity> getRolloutGroupTargets(@PathVariable("rolloutId") final Long rolloutId, + @PathVariable("groupId") final Long groupId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { findRolloutOrThrowException(rolloutId); final RolloutGroup rolloutGroup = findRolloutGroupOrThrowException(groupId); @@ -210,16 +230,15 @@ public class RolloutResource implements RolloutRestApi { final Page rolloutGroupTargets; if (rsqlParam != null) { - final Specification rsqlSpecification = RSQLUtility.parse(rsqlParam, TargetFields.class); - rolloutGroupTargets = this.rolloutGroupManagement.findRolloutGroupTargets(rolloutGroup, rsqlSpecification, + rolloutGroupTargets = this.rolloutGroupManagement.findRolloutGroupTargets(rolloutGroup, rsqlParam, pageable); } else { final Page pageTargets = this.rolloutGroupManagement.findRolloutGroupTargets(rolloutGroup, pageable); rolloutGroupTargets = pageTargets; } - final List rest = TargetMapper.toResponse(rolloutGroupTargets.getContent()); - return new ResponseEntity<>(new PagedList(rest, rolloutGroupTargets.getTotalElements()), + final List rest = MgmtTargetMapper.toResponse(rolloutGroupTargets.getContent()); + return new ResponseEntity<>(new PagedList(rest, rolloutGroupTargets.getTotalElements()), HttpStatus.OK); } @@ -239,7 +258,7 @@ public class RolloutResource implements RolloutRestApi { return rolloutGroup; } - private DistributionSet findDistributionSetOrThrowException(final RolloutRestRequestBody rolloutRequestBody) { + private DistributionSet findDistributionSetOrThrowException(final MgmtRolloutRestRequestBody rolloutRequestBody) { final DistributionSet ds = this.distributionSetManagement .findDistributionSetById(rolloutRequestBody.getDistributionSetId()); if (ds == null) { diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java new file mode 100644 index 000000000..adc19df0a --- /dev/null +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java @@ -0,0 +1,204 @@ +/** + * 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.mgmt.rest.resource; + +import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; +import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata; +import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact; +import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifactHash; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.SoftwareManagement; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.model.Artifact; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; + +/** + * A mapper which maps repository model to RESTful model representation and + * back. + * + */ +public final class MgmtSoftwareModuleMapper { + private MgmtSoftwareModuleMapper() { + // Utility class + } + + private static SoftwareModuleType getSoftwareModuleTypeFromKeyString(final String type, + final SoftwareManagement softwareManagement) { + + final SoftwareModuleType smType = softwareManagement.findSoftwareModuleTypeByKey(type.trim()); + + if (smType == null) { + throw new EntityNotFoundException(type.trim()); + } + + return smType; + } + + static SoftwareModule fromRequest(final EntityFactory entityFactory, + final MgmtSoftwareModuleRequestBodyPost smsRest, final SoftwareManagement softwareManagement) { + return entityFactory.generateSoftwareModule( + getSoftwareModuleTypeFromKeyString(smsRest.getType(), softwareManagement), smsRest.getName(), + smsRest.getVersion(), smsRest.getDescription(), smsRest.getVendor()); + } + + static List fromRequestSwMetadata(final EntityFactory entityFactory, + final SoftwareModule sw, final List metadata) { + final List mappedList = new ArrayList<>(metadata.size()); + for (final MgmtMetadata metadataRest : metadata) { + if (metadataRest.getKey() == null) { + throw new IllegalArgumentException("the key of the metadata must be present"); + } + mappedList.add( + entityFactory.generateSoftwareModuleMetadata(sw, metadataRest.getKey(), metadataRest.getValue())); + } + return mappedList; + } + + static List smFromRequest(final EntityFactory entityFactory, + final Iterable smsRest, final SoftwareManagement softwareManagement) { + final List mappedList = new ArrayList<>(); + for (final MgmtSoftwareModuleRequestBodyPost smRest : smsRest) { + mappedList.add(fromRequest(entityFactory, smRest, softwareManagement)); + } + return mappedList; + } + + /** + * Create response for sw modules. + * + * @param baseSoftareModules + * the modules + * @return the response + */ + public static List toResponse(final List baseSoftareModules) { + final List mappedList = new ArrayList<>(); + if (baseSoftareModules != null) { + for (final SoftwareModule target : baseSoftareModules) { + final MgmtSoftwareModule response = toResponse(target); + + mappedList.add(response); + } + } + return mappedList; + } + + static List toResponseSoftwareModules(final Iterable softwareModules) { + final List response = new ArrayList<>(); + for (final SoftwareModule softwareModule : softwareModules) { + response.add(toResponse(softwareModule)); + } + return response; + } + + static List toResponseSwMetadata(final List metadata) { + final List mappedList = new ArrayList<>(metadata.size()); + for (final SoftwareModuleMetadata distributionSetMetadata : metadata) { + mappedList.add(toResponseSwMetadata(distributionSetMetadata)); + } + return mappedList; + } + + static MgmtMetadata toResponseSwMetadata(final SoftwareModuleMetadata metadata) { + final MgmtMetadata metadataRest = new MgmtMetadata(); + metadataRest.setKey(metadata.getKey()); + metadataRest.setValue(metadata.getValue()); + return metadataRest; + } + + /** + * Create response for one sw module. + * + * @param baseSofwareModule + * the sw module + * @return the response + */ + public static MgmtSoftwareModule toResponse(final SoftwareModule baseSofwareModule) { + if (baseSofwareModule == null) { + return null; + } + + final MgmtSoftwareModule response = new MgmtSoftwareModule(); + MgmtRestModelMapper.mapNamedToNamed(response, baseSofwareModule); + response.setModuleId(baseSofwareModule.getId()); + response.setVersion(baseSofwareModule.getVersion()); + response.setType(baseSofwareModule.getType().getKey()); + response.setVendor(baseSofwareModule.getVendor()); + + response.add(linkTo(methodOn(MgmtSoftwareModuleRestApi.class).getArtifacts(response.getModuleId())) + .withRel(MgmtRestConstants.SOFTWAREMODULE_V1_ARTIFACT)); + response.add(linkTo(methodOn(MgmtSoftwareModuleRestApi.class).getSoftwareModule(response.getModuleId())) + .withRel("self")); + + response.add(linkTo(methodOn(MgmtSoftwareModuleTypeRestApi.class) + .getSoftwareModuleType(baseSofwareModule.getType().getId())) + .withRel(MgmtRestConstants.SOFTWAREMODULE_V1_TYPE)); + + response.add(linkTo(methodOn(MgmtSoftwareModuleResource.class).getMetadata(response.getModuleId(), + Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET), + Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT), null, null)) + .withRel("metadata")); + return response; + } + + /** + * @param artifact + * @return + */ + static MgmtArtifact toResponse(final Artifact artifact) { + final MgmtArtifact.ArtifactType type = artifact instanceof LocalArtifact ? MgmtArtifact.ArtifactType.LOCAL + : MgmtArtifact.ArtifactType.EXTERNAL; + + final MgmtArtifact artifactRest = new MgmtArtifact(); + artifactRest.setType(type); + artifactRest.setArtifactId(artifact.getId()); + artifactRest.setSize(artifact.getSize()); + artifactRest.setHashes(new MgmtArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash())); + + if (artifact instanceof LocalArtifact) { + artifactRest.setProvidedFilename(((LocalArtifact) artifact).getFilename()); + } + + MgmtRestModelMapper.mapBaseToBase(artifactRest, artifact); + + artifactRest.add(linkTo(methodOn(MgmtSoftwareModuleRestApi.class) + .getArtifact(artifact.getSoftwareModule().getId(), artifact.getId())).withRel("self")); + + if (artifact instanceof LocalArtifact) { + artifactRest.add(linkTo(methodOn(MgmtDownloadArtifactResource.class) + .downloadArtifact(artifact.getSoftwareModule().getId(), artifact.getId())).withRel("download")); + } + + return artifactRest; + } + + static List artifactsToResponse(final List artifacts) { + final List mappedList = new ArrayList<>(); + + if (artifacts != null) { + for (final Artifact artifact : artifacts) { + final MgmtArtifact response = toResponse(artifact); + mappedList.add(response); + } + } + return mappedList; + } +} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java similarity index 50% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java index 830443cbd..b475c473f 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java @@ -6,28 +6,27 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import java.io.IOException; import java.util.List; +import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPut; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi; import org.eclipse.hawkbit.repository.ArtifactManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.SoftwareManagement; -import org.eclipse.hawkbit.repository.SoftwareModuleFields; -import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.model.SwMetadataCompositeKey; -import org.eclipse.hawkbit.repository.rsql.RSQLUtility; -import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleRestAPI; -import org.eclipse.hawkbit.rest.resource.model.MetadataRest; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactRest; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -40,6 +39,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @@ -49,8 +49,8 @@ import org.springframework.web.multipart.MultipartFile; * */ @RestController -public class SoftwareModuleResource implements SoftwareModuleRestAPI { - private static final Logger LOG = LoggerFactory.getLogger(SoftwareModuleResource.class); +public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi { + private static final Logger LOG = LoggerFactory.getLogger(MgmtSoftwareModuleResource.class); @Autowired private ArtifactManagement artifactManagement; @@ -58,56 +58,59 @@ public class SoftwareModuleResource implements SoftwareModuleRestAPI { @Autowired private SoftwareManagement softwareManagement; + @Autowired + private EntityFactory entityFactory; + @Override - public ResponseEntity uploadArtifact(@PathVariable final Long softwareModuleId, + public ResponseEntity uploadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, @RequestParam("file") final MultipartFile file, @RequestParam(value = "filename", required = false) final String optionalFileName, @RequestParam(value = "md5sum", required = false) final String md5Sum, @RequestParam(value = "sha1sum", required = false) final String sha1Sum) { - Artifact result; - if (!file.isEmpty()) { - String fileName = optionalFileName; - - if (null == fileName) { - fileName = file.getOriginalFilename(); - } - - try { - result = artifactManagement.createLocalArtifact(file.getInputStream(), softwareModuleId, fileName, - md5Sum == null ? null : md5Sum.toLowerCase(), sha1Sum == null ? null : sha1Sum.toLowerCase(), - false, file.getContentType()); - } catch (final IOException e) { - LOG.error("Failed to store artifact", e); - return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); - } - } else { + if (file.isEmpty()) { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } + String fileName = optionalFileName; - return new ResponseEntity<>(SoftwareModuleMapper.toResponse(result), HttpStatus.CREATED); + if (fileName == null) { + fileName = file.getOriginalFilename(); + } + try { + final Artifact result = artifactManagement.createLocalArtifact(file.getInputStream(), softwareModuleId, + fileName, md5Sum == null ? null : md5Sum.toLowerCase(), + sha1Sum == null ? null : sha1Sum.toLowerCase(), false, file.getContentType()); + return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponse(result), HttpStatus.CREATED); + } catch (final IOException e) { + LOG.error("Failed to store artifact", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } } @Override - public ResponseEntity> getArtifacts(@PathVariable final Long softwareModuleId) { + @ResponseBody + public ResponseEntity> getArtifacts( + @PathVariable("softwareModuleId") final Long softwareModuleId) { final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); - return new ResponseEntity<>(SoftwareModuleMapper.artifactsToResponse(module.getArtifacts()), HttpStatus.OK); + return new ResponseEntity<>(MgmtSoftwareModuleMapper.artifactsToResponse(module.getArtifacts()), HttpStatus.OK); } @Override - public ResponseEntity getArtifact(@PathVariable final Long softwareModuleId, - @PathVariable final Long artifactId) { + @ResponseBody + public ResponseEntity getArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("artifactId") final Long artifactId) { final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId); - return new ResponseEntity<>(SoftwareModuleMapper.toResponse(module.getLocalArtifact(artifactId).get()), + return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponse(module.getLocalArtifact(artifactId).get()), HttpStatus.OK); } @Override - public ResponseEntity deleteArtifact(@PathVariable final Long softwareModuleId, - @PathVariable final Long artifactId) { + @ResponseBody + public ResponseEntity deleteArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("artifactId") final Long artifactId) { findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId); artifactManagement.deleteLocalArtifact(artifactId); @@ -117,11 +120,11 @@ public class SoftwareModuleResource implements SoftwareModuleRestAPI { } @Override - public ResponseEntity> getSoftwareModules( - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { + public ResponseEntity> getSoftwareModules( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -132,40 +135,41 @@ public class SoftwareModuleResource implements SoftwareModuleRestAPI { final Slice findModulesAll; Long countModulesAll; if (rsqlParam != null) { - findModulesAll = softwareManagement - .findSoftwareModulesByPredicate(RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class), pageable); + findModulesAll = softwareManagement.findSoftwareModulesByPredicate(rsqlParam, pageable); countModulesAll = ((Page) findModulesAll).getTotalElements(); } else { findModulesAll = softwareManagement.findSoftwareModulesAll(pageable); countModulesAll = softwareManagement.countSoftwareModulesAll(); } - final List rest = SoftwareModuleMapper.toResponse(findModulesAll.getContent()); + final List rest = MgmtSoftwareModuleMapper.toResponse(findModulesAll.getContent()); return new ResponseEntity<>(new PagedList<>(rest, countModulesAll), HttpStatus.OK); } @Override - public ResponseEntity getSoftwareModule(@PathVariable final Long softwareModuleId) { + public ResponseEntity getSoftwareModule( + @PathVariable("softwareModuleId") final Long softwareModuleId) { final SoftwareModule findBaseSoftareModule = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); - return new ResponseEntity<>(SoftwareModuleMapper.toResponse(findBaseSoftareModule), HttpStatus.OK); + return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponse(findBaseSoftareModule), HttpStatus.OK); } @Override - public ResponseEntity> createSoftwareModules( - @RequestBody final List softwareModules) { + public ResponseEntity> createSoftwareModules( + @RequestBody final List softwareModules) { LOG.debug("creating {} softwareModules", softwareModules.size()); - final Iterable createdSoftwareModules = softwareManagement - .createSoftwareModule(SoftwareModuleMapper.smFromRequest(softwareModules, softwareManagement)); + final Iterable createdSoftwareModules = softwareManagement.createSoftwareModule( + MgmtSoftwareModuleMapper.smFromRequest(entityFactory, softwareModules, softwareManagement)); LOG.debug("{} softwareModules created, return status {}", softwareModules.size(), HttpStatus.CREATED); - return new ResponseEntity<>(SoftwareModuleMapper.toResponseSoftwareModules(createdSoftwareModules), + return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponseSoftwareModules(createdSoftwareModules), HttpStatus.CREATED); } @Override - public ResponseEntity updateSoftwareModule(@PathVariable final Long softwareModuleId, - @RequestBody final SoftwareModuleRequestBodyPut restSoftwareModule) { + public ResponseEntity updateSoftwareModule( + @PathVariable("softwareModuleId") final Long softwareModuleId, + @RequestBody final MgmtSoftwareModuleRequestBodyPut restSoftwareModule) { final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); // only description and vendor can be modified @@ -177,11 +181,11 @@ public class SoftwareModuleResource implements SoftwareModuleRestAPI { } final SoftwareModule updateSoftwareModule = softwareManagement.updateSoftwareModule(module); - return new ResponseEntity<>(SoftwareModuleMapper.toResponse(updateSoftwareModule), HttpStatus.OK); + return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponse(updateSoftwareModule), HttpStatus.OK); } @Override - public ResponseEntity deleteSoftwareModule(@PathVariable final Long softwareModuleId) { + public ResponseEntity deleteSoftwareModule(@PathVariable("softwareModuleId") final Long softwareModuleId) { final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); softwareManagement.deleteSoftwareModule(module); @@ -190,11 +194,12 @@ public class SoftwareModuleResource implements SoftwareModuleRestAPI { } @Override - public ResponseEntity> getMetadata(@PathVariable final Long softwareModuleId, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = RestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { + public ResponseEntity> getMetadata( + @PathVariable("softwareModuleId") final Long softwareModuleId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { // check if software module exists otherwise throw exception immediately findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); @@ -207,57 +212,53 @@ public class SoftwareModuleResource implements SoftwareModuleRestAPI { final Page metaDataPage; if (rsqlParam != null) { - metaDataPage = softwareManagement.findSoftwareModuleMetadataBySoftwareModuleId(softwareModuleId, - RSQLUtility.parse(rsqlParam, SoftwareModuleMetadataFields.class), pageable); + metaDataPage = softwareManagement.findSoftwareModuleMetadataBySoftwareModuleId(softwareModuleId, rsqlParam, + pageable); } else { metaDataPage = softwareManagement.findSoftwareModuleMetadataBySoftwareModuleId(softwareModuleId, pageable); } return new ResponseEntity<>( - new PagedList<>(SoftwareModuleMapper.toResponseSwMetadata(metaDataPage.getContent()), + new PagedList<>(MgmtSoftwareModuleMapper.toResponseSwMetadata(metaDataPage.getContent()), metaDataPage.getTotalElements()), HttpStatus.OK); } @Override - public ResponseEntity getMetadataValue(@PathVariable final Long softwareModuleId, - @PathVariable final String metadataKey) { - // check if distribution set exists otherwise throw exception - // immediately + public ResponseEntity getMetadataValue(@PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("metadataKey") final String metadataKey) { final SoftwareModule sw = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); - final SoftwareModuleMetadata findOne = softwareManagement.findSoftwareModuleMetadata(new SwMetadataCompositeKey(sw, metadataKey)); - return ResponseEntity. ok(SoftwareModuleMapper.toResponseSwMetadata(findOne)); + final SoftwareModuleMetadata findOne = softwareManagement.findSoftwareModuleMetadata(sw, metadataKey); + return ResponseEntity. ok(MgmtSoftwareModuleMapper.toResponseSwMetadata(findOne)); } @Override - public ResponseEntity updateMetadata(@PathVariable final Long softwareModuleId, - @PathVariable final String metadataKey, @RequestBody final MetadataRest metadata) { - // check if software module exists otherwise throw exception immediately + public ResponseEntity updateMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadata metadata) { final SoftwareModule sw = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); - final SoftwareModuleMetadata updated = softwareManagement - .updateSoftwareModuleMetadata(new SoftwareModuleMetadata(metadataKey, sw, metadata.getValue())); - return ResponseEntity.ok(SoftwareModuleMapper.toResponseSwMetadata(updated)); + final SoftwareModuleMetadata updated = softwareManagement.updateSoftwareModuleMetadata( + entityFactory.generateSoftwareModuleMetadata(sw, metadataKey, metadata.getValue())); + return ResponseEntity.ok(MgmtSoftwareModuleMapper.toResponseSwMetadata(updated)); } @Override - public ResponseEntity deleteMetadata(@PathVariable final Long softwareModuleId, - @PathVariable final String metadataKey) { - // check if software module exists otherwise throw exception immediately + public ResponseEntity deleteMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("metadataKey") final String metadataKey) { final SoftwareModule sw = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); - softwareManagement.deleteSoftwareModuleMetadata(new SwMetadataCompositeKey(sw, metadataKey)); + softwareManagement.deleteSoftwareModuleMetadata(sw, metadataKey); return ResponseEntity.ok().build(); } @Override - public ResponseEntity> createMetadata(@PathVariable final Long softwareModuleId, - @RequestBody final List metadataRest) { - // check if software module exists otherwise throw exception immediately + public ResponseEntity> createMetadata( + @PathVariable("softwareModuleId") final Long softwareModuleId, + @RequestBody final List metadataRest) { final SoftwareModule sw = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); - final List created = softwareManagement - .createSoftwareModuleMetadata(SoftwareModuleMapper.fromRequestSwMetadata(sw, metadataRest)); + final List created = softwareManagement.createSoftwareModuleMetadata( + MgmtSoftwareModuleMapper.fromRequestSwMetadata(entityFactory, sw, metadataRest)); - return new ResponseEntity<>(SoftwareModuleMapper.toResponseSwMetadata(created), HttpStatus.CREATED); + return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponseSwMetadata(created), HttpStatus.CREATED); } @@ -271,4 +272,5 @@ public class SoftwareModuleResource implements SoftwareModuleRestAPI { } return module; } + } diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeMapper.java new file mode 100644 index 000000000..565af7eb8 --- /dev/null +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeMapper.java @@ -0,0 +1,90 @@ +/** + * 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.mgmt.rest.resource; + +import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; +import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; + +/** + * A mapper which maps repository model to RESTful model representation and + * back. + * + * + * + * + */ +final class MgmtSoftwareModuleTypeMapper { + + // private constructor, utility class + private MgmtSoftwareModuleTypeMapper() { + + } + + static List smFromRequest(final EntityFactory entityFactory, + final Iterable smTypesRest) { + final List mappedList = new ArrayList<>(); + + for (final MgmtSoftwareModuleTypeRequestBodyPost smRest : smTypesRest) { + mappedList.add(fromRequest(entityFactory, smRest)); + } + return mappedList; + } + + static SoftwareModuleType fromRequest(final EntityFactory entityFactory, + final MgmtSoftwareModuleTypeRequestBodyPost smsRest) { + final SoftwareModuleType result = entityFactory.generateSoftwareModuleType(); + result.setName(smsRest.getName()); + result.setKey(smsRest.getKey()); + result.setDescription(smsRest.getDescription()); + result.setMaxAssignments(smsRest.getMaxAssignments()); + + return result; + } + + static List toTypesResponse(final List types) { + final List response = new ArrayList<>(); + for (final SoftwareModuleType softwareModule : types) { + response.add(toResponse(softwareModule)); + } + return response; + } + + static List toListResponse(final Collection types) { + final List response = new ArrayList<>(); + for (final SoftwareModuleType softwareModule : types) { + response.add(toResponse(softwareModule)); + } + return response; + } + + static MgmtSoftwareModuleType toResponse(final SoftwareModuleType type) { + final MgmtSoftwareModuleType result = new MgmtSoftwareModuleType(); + + MgmtRestModelMapper.mapNamedToNamed(result, type); + result.setKey(type.getKey()); + result.setMaxAssignments(type.getMaxAssignments()); + result.setModuleId(type.getId()); + + result.add(linkTo(methodOn(MgmtSoftwareModuleTypeRestApi.class).getSoftwareModuleType(result.getModuleId())) + .withRel("self")); + + return result; + } + +} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResource.java similarity index 55% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResource.java index e3498f141..353cf16e5 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResource.java @@ -6,22 +6,23 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import java.util.List; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost; +import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPut; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.SoftwareManagement; -import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.rsql.RSQLUtility; -import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleTypeRestApi; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -29,6 +30,9 @@ import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** @@ -37,13 +41,19 @@ import org.springframework.web.bind.annotation.RestController; * */ @RestController -public class SoftwareModuleTypeResource implements SoftwareModuleTypeRestApi { +public class MgmtSoftwareModuleTypeResource implements MgmtSoftwareModuleTypeRestApi { @Autowired private SoftwareManagement softwareManagement; + @Autowired + private EntityFactory entityFactory; + @Override - public ResponseEntity> getTypes(final int pagingOffsetParam, - final int pagingLimitParam, final String sortParam, final String rsqlParam) { + public ResponseEntity> getTypes( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -54,28 +64,29 @@ public class SoftwareModuleTypeResource implements SoftwareModuleTypeRestApi { final Slice findModuleTypessAll; Long countModulesAll; if (rsqlParam != null) { - findModuleTypessAll = this.softwareManagement.findSoftwareModuleTypesByPredicate( - RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class), pageable); + findModuleTypessAll = this.softwareManagement.findSoftwareModuleTypesAll(rsqlParam, pageable); countModulesAll = ((Page) findModuleTypessAll).getTotalElements(); } else { findModuleTypessAll = this.softwareManagement.findSoftwareModuleTypesAll(pageable); countModulesAll = this.softwareManagement.countSoftwareModuleTypesAll(); } - final List rest = SoftwareModuleTypeMapper + final List rest = MgmtSoftwareModuleTypeMapper .toListResponse(findModuleTypessAll.getContent()); return new ResponseEntity<>(new PagedList<>(rest, countModulesAll), HttpStatus.OK); } @Override - public ResponseEntity getSoftwareModuleType(final Long softwareModuleTypeId) { + public ResponseEntity getSoftwareModuleType( + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) { final SoftwareModuleType foundType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId); - return new ResponseEntity<>(SoftwareModuleTypeMapper.toResponse(foundType), HttpStatus.OK); + return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toResponse(foundType), HttpStatus.OK); } @Override - public ResponseEntity deleteSoftwareModuleType(final Long softwareModuleTypeId) { + public ResponseEntity deleteSoftwareModuleType( + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) { final SoftwareModuleType module = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId); this.softwareManagement.deleteSoftwareModuleType(module); @@ -84,8 +95,9 @@ public class SoftwareModuleTypeResource implements SoftwareModuleTypeRestApi { } @Override - public ResponseEntity updateSoftwareModuleType(final Long softwareModuleTypeId, - final SoftwareModuleTypeRequestBodyPut restSoftwareModuleType) { + public ResponseEntity updateSoftwareModuleType( + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId, + @RequestBody final MgmtSoftwareModuleTypeRequestBodyPut restSoftwareModuleType) { final SoftwareModuleType type = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId); // only description can be modified @@ -94,17 +106,17 @@ public class SoftwareModuleTypeResource implements SoftwareModuleTypeRestApi { } final SoftwareModuleType updatedSoftwareModuleType = this.softwareManagement.updateSoftwareModuleType(type); - return new ResponseEntity<>(SoftwareModuleTypeMapper.toResponse(updatedSoftwareModuleType), HttpStatus.OK); + return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toResponse(updatedSoftwareModuleType), HttpStatus.OK); } @Override - public ResponseEntity> createSoftwareModuleTypes( - final List softwareModuleTypes) { + public ResponseEntity> createSoftwareModuleTypes( + @RequestBody final List softwareModuleTypes) { - final List createdSoftwareModules = this.softwareManagement - .createSoftwareModuleType(SoftwareModuleTypeMapper.smFromRequest(softwareModuleTypes)); + final List createdSoftwareModules = this.softwareManagement.createSoftwareModuleType( + MgmtSoftwareModuleTypeMapper.smFromRequest(entityFactory, softwareModuleTypes)); - return new ResponseEntity<>(SoftwareModuleTypeMapper.toTypesResponse(createdSoftwareModules), + return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toTypesResponse(createdSoftwareModules), HttpStatus.CREATED); } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SystemManagementResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemManagementResource.java similarity index 63% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SystemManagementResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemManagementResource.java index 27cfdb924..3392d2659 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SystemManagementResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemManagementResource.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import java.util.Collection; import java.util.Collections; @@ -14,46 +14,36 @@ import java.util.List; import java.util.stream.Collectors; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.report.model.SystemUsageReport; -import org.eclipse.hawkbit.report.model.TenantUsage; +import org.eclipse.hawkbit.mgmt.json.model.systemmanagement.MgmtSystemCache; +import org.eclipse.hawkbit.mgmt.json.model.systemmanagement.MgmtSystemStatisticsRest; +import org.eclipse.hawkbit.mgmt.json.model.systemmanagement.MgmtSystemTenantServiceUsage; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtSystemManagementRestApi; import org.eclipse.hawkbit.repository.SystemManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.rest.resource.model.systemmanagement.CacheRest; -import org.eclipse.hawkbit.rest.resource.model.systemmanagement.SystemStatisticsRest; -import org.eclipse.hawkbit.rest.resource.model.systemmanagement.TenantSystemUsageRest; +import org.eclipse.hawkbit.repository.report.model.SystemUsageReport; +import org.eclipse.hawkbit.repository.report.model.TenantUsage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; /** * {@link SystemManagement} capabilities by REST. * - * - * - * */ @RestController -@RequestMapping(RestConstants.SYSTEM_ADMIN_MAPPING) -public class SystemManagementResource { +public class MgmtSystemManagementResource implements MgmtSystemManagementRestApi { - private static final Logger LOGGER = LoggerFactory.getLogger(SystemManagementResource.class); + private static final Logger LOGGER = LoggerFactory.getLogger(MgmtSystemManagementResource.class); @Autowired private SystemManagement systemManagement; - @Autowired - private TenantConfigurationManagement tenantConfigurationManagement; - @Autowired private CacheManager cacheManager; @@ -64,10 +54,9 @@ public class SystemManagementResource { * to delete * @return HttpStatus.OK */ - @RequestMapping(method = RequestMethod.DELETE, value = "/tenants/{tenant}") - public ResponseEntity deleteTenant(@PathVariable final String tenant) { + @Override + public ResponseEntity deleteTenant(@PathVariable("tenant") final String tenant) { systemManagement.deleteTenant(tenant); - return new ResponseEntity<>(HttpStatus.OK); } @@ -77,24 +66,23 @@ public class SystemManagementResource { * * @return system usage statistics */ - @RequestMapping(method = RequestMethod.GET, value = "/usage", produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getSystemUsageStats() { + @Override + public ResponseEntity getSystemUsageStats() { final SystemUsageReport report = systemManagement.getSystemUsageStatistics(); - final SystemStatisticsRest result = new SystemStatisticsRest().setOverallActions(report.getOverallActions()) - .setOverallArtifacts(report.getOverallArtifacts()) + final MgmtSystemStatisticsRest result = new MgmtSystemStatisticsRest() + .setOverallActions(report.getOverallActions()).setOverallArtifacts(report.getOverallArtifacts()) .setOverallArtifactVolumeInBytes(report.getOverallArtifactVolumeInBytes()) .setOverallTargets(report.getOverallTargets()).setOverallTenants(report.getTenants().size()); - result.setTenantStats( - report.getTenants().stream().map(SystemManagementResource::convertTenant).collect(Collectors.toList())); + result.setTenantStats(report.getTenants().stream().map(MgmtSystemManagementResource::convertTenant) + .collect(Collectors.toList())); return ResponseEntity.ok(result); } - private static TenantSystemUsageRest convertTenant(final TenantUsage tenant) { - final TenantSystemUsageRest result = new TenantSystemUsageRest(tenant.getTenantName()); + private static MgmtSystemTenantServiceUsage convertTenant(final TenantUsage tenant) { + final MgmtSystemTenantServiceUsage result = new MgmtSystemTenantServiceUsage(tenant.getTenantName()); result.setActions(tenant.getActions()); result.setArtifacts(tenant.getArtifacts()); result.setOverallArtifactVolumeInBytes(tenant.getOverallArtifactVolumeInBytes()); @@ -108,9 +96,9 @@ public class SystemManagementResource { * * @return a list of caches for all tenants */ - @RequestMapping(method = RequestMethod.GET, value = "/caches") + @Override @PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN) - public ResponseEntity> getCaches() { + public ResponseEntity> getCaches() { final Collection cacheNames = cacheManager.getCacheNames(); return ResponseEntity .ok(cacheNames.stream().map(cacheManager::getCache).map(this::cacheRest).collect(Collectors.toList())); @@ -121,8 +109,8 @@ public class SystemManagementResource { * * @return a list of cache names which has been invalidated */ - @RequestMapping(method = RequestMethod.DELETE, value = "/caches") @PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN) + @Override public ResponseEntity> invalidateCaches() { final Collection cacheNames = cacheManager.getCacheNames(); LOGGER.info("Invalidating caches {}", cacheNames); @@ -130,20 +118,20 @@ public class SystemManagementResource { return ResponseEntity.ok(cacheNames); } - private CacheRest cacheRest(final Cache cache) { + private MgmtSystemCache cacheRest(final Cache cache) { final Object nativeCache = cache.getNativeCache(); if (nativeCache instanceof com.google.common.cache.Cache) { return guavaCache(cache, nativeCache); } else { - return new CacheRest(cache.getName(), Collections.emptyList()); + return new MgmtSystemCache(cache.getName(), Collections.emptyList()); } } @SuppressWarnings("unchecked") - private CacheRest guavaCache(final Cache cache, final Object nativeCache) { + private MgmtSystemCache guavaCache(final Cache cache, final Object nativeCache) { final com.google.common.cache.Cache guavaCache = (com.google.common.cache.Cache) nativeCache; final List keys = guavaCache.asMap().keySet().stream().map(key -> key.toString()) .collect(Collectors.toList()); - return new CacheRest(cache.getName(), keys); + return new MgmtSystemCache(cache.getName(), keys); } } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SystemMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemMapper.java similarity index 74% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SystemMapper.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemMapper.java index 0f8119b53..d3f78fad2 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SystemMapper.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemMapper.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; @@ -14,18 +14,18 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; import java.util.HashMap; import java.util.Map; +import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValue; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.rest.resource.model.system.TenantConfigurationValueRest; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; /** * A mapper which maps repository model to RESTful model representation and * back. */ -public class SystemMapper { +public class MgmtSystemMapper { - private SystemMapper() { + private MgmtSystemMapper() { // Utility class } @@ -34,10 +34,10 @@ public class SystemMapper { * instance of TenantConfigurationManagement * @return a map of all existing configuration values */ - public static Map toResponse( + public static Map toResponse( final TenantConfigurationManagement tenantConfigurationManagement) { - final Map configurationMap = new HashMap<>(); + final Map configurationMap = new HashMap<>(); for (final TenantConfigurationKey key : TenantConfigurationKey.values()) { configurationMap.put(key.getKeyName(), @@ -49,15 +49,15 @@ public class SystemMapper { /** * maps a TenantConfigurationValue from the repository model to a - * TenantConfigurationValueRest, the RESTful model. + * MgmtSystemTenantConfigurationValue, the RESTful model. * * @param repoConfValue * configuration value as repository model * @return configuration value as RESTful model */ - public static TenantConfigurationValueRest toResponse(final String key, + public static MgmtSystemTenantConfigurationValue toResponse(final String key, final TenantConfigurationValue repoConfValue) { - final TenantConfigurationValueRest restConfValue = new TenantConfigurationValueRest(); + final MgmtSystemTenantConfigurationValue restConfValue = new MgmtSystemTenantConfigurationValue(); restConfValue.setValue(repoConfValue.getValue()); restConfValue.setGlobal(repoConfValue.isGlobal()); @@ -66,7 +66,7 @@ public class SystemMapper { restConfValue.setLastModifiedAt(repoConfValue.getLastModifiedAt()); restConfValue.setLastModifiedBy(repoConfValue.getLastModifiedBy()); - restConfValue.add(linkTo(methodOn(SystemResource.class).getConfigurationValue(key)).withRel("self")); + restConfValue.add(linkTo(methodOn(MgmtSystemResource.class).getConfigurationValue(key)).withRel("self")); return restConfValue; } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SystemResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemResource.java similarity index 62% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SystemResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemResource.java index 9f2201868..fb9218d31 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SystemResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemResource.java @@ -6,61 +6,53 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; import java.util.Map; +import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValue; +import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValueRequest; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtSystemRestApi; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.rest.resource.model.system.TenantConfigurationValueRequest; -import org.eclipse.hawkbit.rest.resource.model.system.TenantConfigurationValueRest; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.ResourceSupport; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; /** * REST Resource handling tenant specific configuration operations. - * - * - * - * */ @RestController -@RequestMapping(RestConstants.SYSTEM_V1_REQUEST_MAPPING) -public class SystemResource { +public class MgmtSystemResource implements MgmtSystemRestApi { - private static final Logger LOG = LoggerFactory.getLogger(SystemResource.class); + private static final Logger LOG = LoggerFactory.getLogger(MgmtSystemResource.class); @Autowired private TenantConfigurationManagement tenantConfigurationManagement; - @RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity getSystem() { final ResourceSupport resourceSupport = new ResourceSupport(); - resourceSupport.add(linkTo(methodOn(SystemResource.class).getSystemConfiguration()).withRel("configs")); + resourceSupport.add(linkTo(methodOn(MgmtSystemResource.class).getSystemConfiguration()).withRel("configs")); return ResponseEntity.ok(resourceSupport); } /** * @return a Map of all configuration values. */ - @RequestMapping(method = RequestMethod.GET, value = "/configs", produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity> getSystemConfiguration() { - return new ResponseEntity<>(SystemMapper.toResponse(tenantConfigurationManagement), HttpStatus.OK); + @Override + public ResponseEntity> getSystemConfiguration() { + return new ResponseEntity<>(MgmtSystemMapper.toResponse(tenantConfigurationManagement), HttpStatus.OK); } /** @@ -73,9 +65,8 @@ public class SystemResource { * OK. In any failure the JsonResponseExceptionHandler is handling * the response. */ - @RequestMapping(method = RequestMethod.DELETE, value = "/configs/{keyName}", produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity deleteConfigurationValue(@PathVariable final String keyName) { + @Override + public ResponseEntity deleteConfigurationValue(@PathVariable("keyName") final String keyName) { final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName); @@ -95,14 +86,14 @@ public class SystemResource { * In any failure the JsonResponseExceptionHandler is handling the * response. */ - @RequestMapping(method = RequestMethod.GET, value = "/configs/{keyName}", produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getConfigurationValue(@PathVariable final String keyName) { + @Override + public ResponseEntity getConfigurationValue( + @PathVariable("keyName") final String keyName) { final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName); LOG.debug("{} config value getted, return status {}", keyName, HttpStatus.OK); - return new ResponseEntity<>(SystemMapper.toResponse(configKey.getKeyName(), + return new ResponseEntity<>(MgmtSystemMapper.toResponse(configKey.getKeyName(), tenantConfigurationManagement.getConfigurationValue(configKey)), HttpStatus.OK); } @@ -118,17 +109,18 @@ public class SystemResource { * In any failure the JsonResponseExceptionHandler is handling the * response. */ - @RequestMapping(method = RequestMethod.PUT, value = "/configs/{keyName}", consumes = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity updateConfigurationValue(@PathVariable final String keyName, - @RequestBody final TenantConfigurationValueRequest configurationValueRest) { + @Override + public ResponseEntity updateConfigurationValue( + @PathVariable("keyName") final String keyName, + @RequestBody final MgmtSystemTenantConfigurationValueRequest configurationValueRest) { final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName); final TenantConfigurationValue updatedValue = tenantConfigurationManagement .addOrUpdateConfiguration(configKey, configurationValueRest.getValue()); - return new ResponseEntity<>(SystemMapper.toResponse(keyName, updatedValue), HttpStatus.OK); + return new ResponseEntity<>(MgmtSystemMapper.toResponse(keyName, updatedValue), HttpStatus.OK); } -} \ No newline at end of file +} + diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TagMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTagMapper.java similarity index 51% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TagMapper.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTagMapper.java index f9f0caba0..bac21c2a5 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TagMapper.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTagMapper.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; @@ -14,111 +14,115 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; import java.util.ArrayList; import java.util.List; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTagRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi; +import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.Tag; import org.eclipse.hawkbit.repository.model.TargetTag; -import org.eclipse.hawkbit.rest.resource.api.DistributionSetTagRestApi; -import org.eclipse.hawkbit.rest.resource.api.TargetTagRestApi; -import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.tag.TagRest; /** * A mapper which maps repository model to RESTful model representation and * back. * */ -final class TagMapper { - private TagMapper() { +final class MgmtTagMapper { + private MgmtTagMapper() { // Utility class } - static List toResponse(final List targetTags) { - final List tagsRest = new ArrayList<>(); + static List toResponse(final List targetTags) { + final List tagsRest = new ArrayList<>(); if (targetTags == null) { return tagsRest; } for (final TargetTag target : targetTags) { - final TagRest response = toResponse(target); + final MgmtTag response = toResponse(target); tagsRest.add(response); } return tagsRest; } - static TagRest toResponse(final TargetTag targetTag) { - final TagRest response = new TagRest(); + static MgmtTag toResponse(final TargetTag targetTag) { + final MgmtTag response = new MgmtTag(); if (targetTag == null) { return response; } mapTag(response, targetTag); - response.add(linkTo(methodOn(TargetTagRestApi.class).getTargetTag(targetTag.getId())).withRel("self")); + response.add(linkTo(methodOn(MgmtTargetTagRestApi.class).getTargetTag(targetTag.getId())).withRel("self")); - response.add(linkTo(methodOn(TargetTagRestApi.class).getAssignedTargets(targetTag.getId())) + response.add(linkTo(methodOn(MgmtTargetTagRestApi.class).getAssignedTargets(targetTag.getId())) .withRel("assignedTargets")); return response; } - static List toResponseDistributionSetTag(final List distributionSetTags) { - final List tagsRest = new ArrayList<>(); + static List toResponseDistributionSetTag(final List distributionSetTags) { + final List tagsRest = new ArrayList<>(); if (distributionSetTags == null) { return tagsRest; } for (final DistributionSetTag distributionSetTag : distributionSetTags) { - final TagRest response = toResponse(distributionSetTag); + final MgmtTag response = toResponse(distributionSetTag); tagsRest.add(response); } return tagsRest; } - static TagRest toResponse(final DistributionSetTag distributionSetTag) { - final TagRest response = new TagRest(); + static MgmtTag toResponse(final DistributionSetTag distributionSetTag) { + final MgmtTag response = new MgmtTag(); if (distributionSetTag == null) { return null; } mapTag(response, distributionSetTag); - response.add(linkTo(methodOn(DistributionSetTagRestApi.class).getDistributionSetTag(distributionSetTag.getId())) - .withRel("self")); + response.add( + linkTo(methodOn(MgmtDistributionSetTagRestApi.class).getDistributionSetTag(distributionSetTag.getId())) + .withRel("self")); response.add(linkTo( - methodOn(DistributionSetTagRestApi.class).getAssignedDistributionSets(distributionSetTag.getId())) + methodOn(MgmtDistributionSetTagRestApi.class).getAssignedDistributionSets(distributionSetTag.getId())) .withRel("assignedDistributionSets")); return response; } - static List mapTargeTagFromRequest(final Iterable tags) { + static List mapTargeTagFromRequest(final EntityFactory entityFactory, + final Iterable tags) { final List mappedList = new ArrayList<>(); - for (final TagRequestBodyPut targetTagRest : tags) { - mappedList.add( - new TargetTag(targetTagRest.getName(), targetTagRest.getDescription(), targetTagRest.getColour())); - } - return mappedList; - } - - static List mapDistributionSetTagFromRequest(final Iterable tags) { - final List mappedList = new ArrayList<>(); - for (final TagRequestBodyPut targetTagRest : tags) { - mappedList.add(new DistributionSetTag(targetTagRest.getName(), targetTagRest.getDescription(), + for (final MgmtTagRequestBodyPut targetTagRest : tags) { + mappedList.add(entityFactory.generateTargetTag(targetTagRest.getName(), targetTagRest.getDescription(), targetTagRest.getColour())); } return mappedList; } - private static void mapTag(final TagRest response, final Tag tag) { - RestModelMapper.mapNamedToNamed(response, tag); + static List mapDistributionSetTagFromRequest(final EntityFactory entityFactory, + final Iterable tags) { + final List mappedList = new ArrayList<>(); + for (final MgmtTagRequestBodyPut targetTagRest : tags) { + mappedList.add(entityFactory.generateDistributionSetTag(targetTagRest.getName(), + targetTagRest.getDescription(), targetTagRest.getColour())); + } + return mappedList; + } + + private static void mapTag(final MgmtTag response, final Tag tag) { + MgmtRestModelMapper.mapNamedToNamed(response, tag); response.setTagId(tag.getId()); response.setColour(tag.getColour()); } - static void updateTag(final TagRequestBodyPut response, final Tag tag) { + static void updateTag(final MgmtTagRequestBodyPut response, final Tag tag) { if (response.getDescription() != null) { tag.setDescription(response.getDescription()); } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetMapper.java similarity index 60% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetMapper.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetMapper.java index c8a39a2f3..a889edc35 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetMapper.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetMapper.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; @@ -17,27 +17,31 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import org.eclipse.hawkbit.mgmt.json.model.MgmtPollStatus; +import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction; +import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionStatus; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi; import org.eclipse.hawkbit.repository.ActionFields; +import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.PollStatus; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo.PollStatus; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.rest.resource.api.TargetRestApi; -import org.eclipse.hawkbit.rest.resource.model.PollStatusRest; -import org.eclipse.hawkbit.rest.resource.model.action.ActionRest; -import org.eclipse.hawkbit.rest.resource.model.action.ActionStatusRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; +import org.eclipse.hawkbit.rest.data.SortDirection; +import org.eclipse.hawkbit.util.IpUtil; /** * A mapper which maps repository model to RESTful model representation and * back. * */ -public final class TargetMapper { +public final class MgmtTargetMapper { - private TargetMapper() { + private MgmtTargetMapper() { // Utility class } @@ -47,17 +51,17 @@ public final class TargetMapper { * @param response * the target response */ - public static void addTargetLinks(final TargetRest response) { - response.add(linkTo(methodOn(TargetRestApi.class).getAssignedDistributionSet(response.getControllerId())) - .withRel(RestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET)); - response.add(linkTo(methodOn(TargetRestApi.class).getInstalledDistributionSet(response.getControllerId())) - .withRel(RestConstants.TARGET_V1_INSTALLED_DISTRIBUTION_SET)); - response.add(linkTo(methodOn(TargetRestApi.class).getAttributes(response.getControllerId())) - .withRel(RestConstants.TARGET_V1_ATTRIBUTES)); - response.add(linkTo(methodOn(TargetRestApi.class).getActionHistory(response.getControllerId(), 0, - RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, + public static void addTargetLinks(final MgmtTarget response) { + response.add(linkTo(methodOn(MgmtTargetRestApi.class).getAssignedDistributionSet(response.getControllerId())) + .withRel(MgmtRestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET)); + response.add(linkTo(methodOn(MgmtTargetRestApi.class).getInstalledDistributionSet(response.getControllerId())) + .withRel(MgmtRestConstants.TARGET_V1_INSTALLED_DISTRIBUTION_SET)); + response.add(linkTo(methodOn(MgmtTargetRestApi.class).getAttributes(response.getControllerId())) + .withRel(MgmtRestConstants.TARGET_V1_ATTRIBUTES)); + response.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionHistory(response.getControllerId(), 0, + MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, ActionFields.ID.getFieldName() + ":" + SortDirection.DESC, null)) - .withRel(RestConstants.TARGET_V1_ACTIONS)); + .withRel(MgmtRestConstants.TARGET_V1_ACTIONS)); } /** @@ -68,10 +72,10 @@ public final class TargetMapper { * @param targetRest * the response */ - public static void addPollStatus(final Target target, final TargetRest targetRest) { + public static void addPollStatus(final Target target, final MgmtTarget targetRest) { final PollStatus pollStatus = target.getTargetInfo().getPollStatus(); if (pollStatus != null) { - final PollStatusRest pollStatusRest = new PollStatusRest(); + final MgmtPollStatus pollStatusRest = new MgmtPollStatus(); pollStatusRest.setLastRequestAt( Date.from(pollStatus.getLastPollDate().atZone(ZoneId.systemDefault()).toInstant()).getTime()); pollStatusRest.setNextExpectedRequestAt( @@ -88,11 +92,11 @@ public final class TargetMapper { * the targets * @return the response */ - public static List toResponseWithLinksAndPollStatus(final Iterable targets) { - final List mappedList = new ArrayList<>(); + public static List toResponseWithLinksAndPollStatus(final Iterable targets) { + final List mappedList = new ArrayList<>(); if (targets != null) { for (final Target target : targets) { - final TargetRest response = toResponse(target); + final MgmtTarget response = toResponse(target); addPollStatus(target, response); addTargetLinks(response); mappedList.add(response); @@ -108,11 +112,11 @@ public final class TargetMapper { * list of targets * @return the response */ - public static List toResponse(final Iterable targets) { - final List mappedList = new ArrayList<>(); + public static List toResponse(final Iterable targets) { + final List mappedList = new ArrayList<>(); if (targets != null) { for (final Target target : targets) { - final TargetRest response = toResponse(target); + final MgmtTarget response = toResponse(target); mappedList.add(response); } } @@ -126,11 +130,11 @@ public final class TargetMapper { * the target * @return the response */ - public static TargetRest toResponse(final Target target) { + public static MgmtTarget toResponse(final Target target) { if (target == null) { return null; } - final TargetRest targetRest = new TargetRest(); + final MgmtTarget targetRest = new MgmtTarget(); targetRest.setControllerId(target.getControllerId()); targetRest.setDescription(target.getDescription()); targetRest.setName(target.getName()); @@ -138,7 +142,9 @@ public final class TargetMapper { final URI address = target.getTargetInfo().getAddress(); if (address != null) { - targetRest.setIpAddress(address.getHost()); + if (IpUtil.isIpAddresKnown(address)) { + targetRest.setIpAddress(address.getHost()); + } targetRest.setAddress(address.toString()); } @@ -161,32 +167,35 @@ public final class TargetMapper { targetRest.setInstalledAt(installationDate); } - targetRest.add(linkTo(methodOn(TargetRestApi.class).getTarget(target.getControllerId())).withRel("self")); + targetRest.add(linkTo(methodOn(MgmtTargetRestApi.class).getTarget(target.getControllerId())).withRel("self")); return targetRest; } - static List fromRequest(final Iterable targetsRest) { + static List fromRequest(final EntityFactory entityFactory, + final Iterable targetsRest) { final List mappedList = new ArrayList<>(); - for (final TargetRequestBody targetRest : targetsRest) { - mappedList.add(fromRequest(targetRest)); + for (final MgmtTargetRequestBody targetRest : targetsRest) { + mappedList.add(fromRequest(entityFactory, targetRest)); } return mappedList; } - static Target fromRequest(final TargetRequestBody targetRest) { - final Target target = new Target(targetRest.getControllerId()); + static Target fromRequest(final EntityFactory entityFactory, final MgmtTargetRequestBody targetRest) { + final Target target = entityFactory.generateTarget(targetRest.getControllerId(), targetRest.getSecurityToken()); target.setDescription(targetRest.getDescription()); target.setName(targetRest.getName()); + target.getTargetInfo().setAddress(targetRest.getAddress()); + return target; } - static List toActionStatusRestResponse(final List actionStatus) { - final List mappedList = new ArrayList<>(); + static List toActionStatusRestResponse(final List actionStatus) { + final List mappedList = new ArrayList<>(); if (actionStatus != null) { for (final ActionStatus status : actionStatus) { - final ActionStatusRest response = toResponse(status); + final MgmtActionStatus response = toResponse(status); mappedList.add(response); } } @@ -194,30 +203,30 @@ public final class TargetMapper { return mappedList; } - static ActionRest toResponse(final String targetId, final Action action, final boolean isActive) { - final ActionRest result = new ActionRest(); + static MgmtAction toResponse(final String targetId, final Action action, final boolean isActive) { + final MgmtAction result = new MgmtAction(); result.setActionId(action.getId()); result.setType(getType(action)); if (isActive) { - result.setStatus(ActionRest.ACTION_PENDING); + result.setStatus(MgmtAction.ACTION_PENDING); } else { - result.setStatus(ActionRest.ACTION_FINISHED); + result.setStatus(MgmtAction.ACTION_FINISHED); } - RestModelMapper.mapBaseToBase(result, action); + MgmtRestModelMapper.mapBaseToBase(result, action); - result.add(linkTo(methodOn(TargetRestApi.class).getAction(targetId, action.getId())).withRel("self")); + result.add(linkTo(methodOn(MgmtTargetRestApi.class).getAction(targetId, action.getId())).withRel("self")); return result; } - static List toResponse(final String targetId, final List actions) { - final List mappedList = new ArrayList<>(); + static List toResponse(final String targetId, final List actions) { + final List mappedList = new ArrayList<>(); for (final Action action : actions) { - final ActionRest response = toResponse(targetId, action, action.isActive()); + final MgmtAction response = toResponse(targetId, action, action.isActive()); mappedList.add(response); } return mappedList; @@ -228,22 +237,22 @@ public final class TargetMapper { switch (type) { case CANCELED: - result = ActionStatusRest.AS_CANCELED; + result = MgmtActionStatus.AS_CANCELED; break; case ERROR: - result = ActionStatusRest.AS_ERROR; + result = MgmtActionStatus.AS_ERROR; break; case FINISHED: - result = ActionStatusRest.AS_FINISHED; + result = MgmtActionStatus.AS_FINISHED; break; case RETRIEVED: - result = ActionStatusRest.AS_RETRIEVED; + result = MgmtActionStatus.AS_RETRIEVED; break; case RUNNING: - result = ActionStatusRest.AS_RUNNING; + result = MgmtActionStatus.AS_RUNNING; break; case WARNING: - result = ActionStatusRest.AS_WARNING; + result = MgmtActionStatus.AS_WARNING; break; default: return type.name().toLowerCase(); @@ -256,9 +265,9 @@ public final class TargetMapper { private static String getType(final Action action) { if (!action.isCancelingOrCanceled()) { - return ActionRest.ACTION_UPDATE; + return MgmtAction.ACTION_UPDATE; } else if (action.isCancelingOrCanceled()) { - return ActionRest.ACTION_CANCEL; + return MgmtAction.ACTION_CANCEL; } return null; @@ -290,8 +299,8 @@ public final class TargetMapper { return result; } - private static ActionStatusRest toResponse(final ActionStatus actionStatus) { - final ActionStatusRest result = new ActionStatusRest(); + private static MgmtActionStatus toResponse(final ActionStatus actionStatus) { + final MgmtActionStatus result = new MgmtActionStatus(); result.setMessages(actionStatus.getMessages()); result.setReportedAt(actionStatus.getCreatedAt()); diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java similarity index 53% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java index 4b068a41e..5ddb74314 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; @@ -15,28 +15,28 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import org.eclipse.hawkbit.repository.ActionFields; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction; +import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionStatus; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtDistributionSetAssigment; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetAttributes; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi; import org.eclipse.hawkbit.repository.ActionStatusFields; import org.eclipse.hawkbit.repository.DeploymentManagement; -import org.eclipse.hawkbit.repository.TargetFields; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.rsql.RSQLUtility; -import org.eclipse.hawkbit.rest.resource.api.DistributionSetRestApi; -import org.eclipse.hawkbit.rest.resource.api.TargetRestApi; -import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.action.ActionRest; -import org.eclipse.hawkbit.rest.resource.model.action.ActionStatusRest; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest; -import org.eclipse.hawkbit.rest.resource.model.target.DistributionSetAssigmentRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetAttributes; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; +import org.eclipse.hawkbit.rest.data.SortDirection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -44,9 +44,10 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; -import org.springframework.data.jpa.domain.Specification; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -54,8 +55,8 @@ import org.springframework.web.bind.annotation.RestController; * REST Resource handling target CRUD operations. */ @RestController -public class TargetResource implements TargetRestApi { - private static final Logger LOG = LoggerFactory.getLogger(TargetResource.class); +public class MgmtTargetResource implements MgmtTargetRestApi { + private static final Logger LOG = LoggerFactory.getLogger(MgmtTargetResource.class); @Autowired private TargetManagement targetManagement; @@ -63,20 +64,26 @@ public class TargetResource implements TargetRestApi { @Autowired private DeploymentManagement deploymentManagement; + @Autowired + private EntityFactory entityFactory; + @Override - public ResponseEntity getTarget(final String targetId) { - final Target findTarget = findTargetWithExceptionIfNotFound(targetId); + public ResponseEntity getTarget(@PathVariable("controllerId") final String controllerId) { + final Target findTarget = findTargetWithExceptionIfNotFound(controllerId); // to single response include poll status - final TargetRest response = TargetMapper.toResponse(findTarget); - TargetMapper.addPollStatus(findTarget, response); - TargetMapper.addTargetLinks(response); + final MgmtTarget response = MgmtTargetMapper.toResponse(findTarget); + MgmtTargetMapper.addPollStatus(findTarget, response); + MgmtTargetMapper.addTargetLinks(response); return new ResponseEntity<>(response, HttpStatus.OK); } @Override - public ResponseEntity> getTargets(final int pagingOffsetParam, final int pagingLimitParam, - final String sortParam, final String rsqlParam) { + public ResponseEntity> getTargets( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -86,8 +93,7 @@ public class TargetResource implements TargetRestApi { final Slice findTargetsAll; final Long countTargetsAll; if (rsqlParam != null) { - final Page findTargetPage = this.targetManagement - .findTargetsAll(RSQLUtility.parse(rsqlParam, TargetFields.class), pageable); + final Page findTargetPage = this.targetManagement.findTargetsAll(rsqlParam, pageable); countTargetsAll = findTargetPage.getTotalElements(); findTargetsAll = findTargetPage; } else { @@ -95,21 +101,23 @@ public class TargetResource implements TargetRestApi { countTargetsAll = this.targetManagement.countTargetsAll(); } - final List rest = TargetMapper.toResponse(findTargetsAll.getContent()); - return new ResponseEntity<>(new PagedList(rest, countTargetsAll), HttpStatus.OK); + final List rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent()); + return new ResponseEntity<>(new PagedList(rest, countTargetsAll), HttpStatus.OK); } @Override - public ResponseEntity> createTargets(final List targets) { + public ResponseEntity> createTargets(@RequestBody final List targets) { LOG.debug("creating {} targets", targets.size()); - final Iterable createdTargets = this.targetManagement.createTargets(TargetMapper.fromRequest(targets)); + final Iterable createdTargets = this.targetManagement + .createTargets(MgmtTargetMapper.fromRequest(entityFactory, targets)); LOG.debug("{} targets created, return status {}", targets.size(), HttpStatus.CREATED); - return new ResponseEntity<>(TargetMapper.toResponse(createdTargets), HttpStatus.CREATED); + return new ResponseEntity<>(MgmtTargetMapper.toResponse(createdTargets), HttpStatus.CREATED); } @Override - public ResponseEntity updateTarget(final String targetId, final TargetRequestBody targetRest) { - final Target existingTarget = findTargetWithExceptionIfNotFound(targetId); + public ResponseEntity updateTarget(@PathVariable("controllerId") final String controllerId, + @RequestBody final MgmtTargetRequestBody targetRest) { + final Target existingTarget = findTargetWithExceptionIfNotFound(controllerId); LOG.debug("updating target {}", existingTarget.getId()); if (targetRest.getDescription() != null) { existingTarget.setDescription(targetRest.getDescription()); @@ -117,38 +125,49 @@ public class TargetResource implements TargetRestApi { if (targetRest.getName() != null) { existingTarget.setName(targetRest.getName()); } + if (targetRest.getAddress() != null) { + existingTarget.getTargetInfo().setAddress(targetRest.getAddress()); + } + if (targetRest.getSecurityToken() != null) { + existingTarget.setSecurityToken(targetRest.getSecurityToken()); + } + final Target updateTarget = this.targetManagement.updateTarget(existingTarget); - return new ResponseEntity<>(TargetMapper.toResponse(updateTarget), HttpStatus.OK); + return new ResponseEntity<>(MgmtTargetMapper.toResponse(updateTarget), HttpStatus.OK); } @Override - public ResponseEntity deleteTarget(final String targetId) { - final Target target = findTargetWithExceptionIfNotFound(targetId); + public ResponseEntity deleteTarget(@PathVariable("controllerId") final String controllerId) { + final Target target = findTargetWithExceptionIfNotFound(controllerId); this.targetManagement.deleteTargets(target.getId()); - LOG.debug("{} target deleted, return status {}", targetId, HttpStatus.OK); + LOG.debug("{} target deleted, return status {}", controllerId, HttpStatus.OK); return new ResponseEntity<>(HttpStatus.OK); } @Override - public ResponseEntity getAttributes(final String targetId) { - final Target foundTarget = findTargetWithExceptionIfNotFound(targetId); + public ResponseEntity getAttributes(@PathVariable("controllerId") final String controllerId) { + final Target foundTarget = findTargetWithExceptionIfNotFound(controllerId); final Map controllerAttributes = foundTarget.getTargetInfo().getControllerAttributes(); if (controllerAttributes.isEmpty()) { return new ResponseEntity<>(HttpStatus.NO_CONTENT); } - final TargetAttributes result = new TargetAttributes(); + final MgmtTargetAttributes result = new MgmtTargetAttributes(); result.putAll(controllerAttributes); return new ResponseEntity<>(result, HttpStatus.OK); } @Override - public ResponseEntity> getActionHistory(final String targetId, final int pagingOffsetParam, - final int pagingLimitParam, final String sortParam, final String rsqlParam) { + public ResponseEntity> getActionHistory( + @PathVariable("controllerId") final String controllerId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { - final Target foundTarget = findTargetWithExceptionIfNotFound(targetId); + final Target foundTarget = findTargetWithExceptionIfNotFound(controllerId); final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -158,22 +177,23 @@ public class TargetResource implements TargetRestApi { final Slice activeActions; final Long totalActionCount; if (rsqlParam != null) { - final Specification parse = RSQLUtility.parse(rsqlParam, ActionFields.class); - activeActions = this.deploymentManagement.findActionsByTarget(parse, foundTarget, pageable); - totalActionCount = this.deploymentManagement.countActionsByTarget(parse, foundTarget); + activeActions = this.deploymentManagement.findActionsByTarget(rsqlParam, foundTarget, pageable); + totalActionCount = this.deploymentManagement.countActionsByTarget(rsqlParam, foundTarget); } else { activeActions = this.deploymentManagement.findActionsByTarget(foundTarget, pageable); totalActionCount = this.deploymentManagement.countActionsByTarget(foundTarget); } return new ResponseEntity<>( - new PagedList<>(TargetMapper.toResponse(targetId, activeActions.getContent()), totalActionCount), + new PagedList<>(MgmtTargetMapper.toResponse(controllerId, activeActions.getContent()), + totalActionCount), HttpStatus.OK); } @Override - public ResponseEntity getAction(final String targetId, final Long actionId) { - final Target target = findTargetWithExceptionIfNotFound(targetId); + public ResponseEntity getAction(@PathVariable("controllerId") final String controllerId, + @PathVariable("actionId") final Long actionId) { + final Target target = findTargetWithExceptionIfNotFound(controllerId); final Action action = findActionWithExceptionIfNotFound(actionId); if (!action.getTarget().getId().equals(target.getId())) { @@ -181,29 +201,30 @@ public class TargetResource implements TargetRestApi { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } - final ActionRest result = TargetMapper.toResponse(targetId, action, action.isActive()); + final MgmtAction result = MgmtTargetMapper.toResponse(controllerId, action, action.isActive()); if (!action.isCancelingOrCanceled()) { result.add(linkTo( - methodOn(DistributionSetRestApi.class).getDistributionSet(action.getDistributionSet().getId())) + methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(action.getDistributionSet().getId())) .withRel("distributionset")); } else if (action.isCancelingOrCanceled()) { - result.add(linkTo(methodOn(TargetRestApi.class).getAction(targetId, action.getId())) - .withRel(RestConstants.TARGET_V1_CANCELED_ACTION)); + result.add(linkTo(methodOn(MgmtTargetRestApi.class).getAction(controllerId, action.getId())) + .withRel(MgmtRestConstants.TARGET_V1_CANCELED_ACTION)); } - result.add(linkTo(methodOn(TargetRestApi.class).getActionStatusList(targetId, action.getId(), 0, - RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, + result.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionStatusList(controllerId, action.getId(), 0, + MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, ActionStatusFields.ID.getFieldName() + ":" + SortDirection.DESC)) - .withRel(RestConstants.TARGET_V1_ACTION_STATUS)); + .withRel(MgmtRestConstants.TARGET_V1_ACTION_STATUS)); return new ResponseEntity<>(result, HttpStatus.OK); } @Override - public ResponseEntity cancelAction(final String targetId, final Long actionId, - @RequestParam(required = false, defaultValue = "false") final boolean force) { - final Target target = findTargetWithExceptionIfNotFound(targetId); + public ResponseEntity cancelAction(@PathVariable("controllerId") final String controllerId, + @PathVariable("actionId") final Long actionId, + @RequestParam(value = "force", required = false, defaultValue = "false") final boolean force) { + final Target target = findTargetWithExceptionIfNotFound(controllerId); final Action action = findActionWithExceptionIfNotFound(actionId); if (force) { @@ -212,16 +233,19 @@ public class TargetResource implements TargetRestApi { this.deploymentManagement.cancelAction(action, target); } // both functions will throw an exception, when action is in wrong - // state, which is mapped by ResponseExceptionHandler. + // state, which is mapped by MgmtResponseExceptionHandler. return new ResponseEntity<>(HttpStatus.NO_CONTENT); } @Override - public ResponseEntity> getActionStatusList(final String targetId, final Long actionId, - final int pagingOffsetParam, final int pagingLimitParam, final String sortParam) { + public ResponseEntity> getActionStatusList( + @PathVariable("controllerId") final String controllerId, @PathVariable("actionId") final Long actionId, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam) { - final Target target = findTargetWithExceptionIfNotFound(targetId); + final Target target = findTargetWithExceptionIfNotFound(controllerId); final Action action = findActionWithExceptionIfNotFound(actionId); if (!action.getTarget().getId().equals(target.getId())) { @@ -233,18 +257,21 @@ public class TargetResource implements TargetRestApi { final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); final Sort sorting = PagingUtility.sanitizeActionStatusSortParam(sortParam); - final Page statusList = this.deploymentManagement.findActionStatusByAction( - new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting), action, true); + final Page statusList = this.deploymentManagement.findActionStatusByActionWithMessages( + new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting), action); - return new ResponseEntity<>(new PagedList<>(TargetMapper.toActionStatusRestResponse(statusList.getContent()), - statusList.getTotalElements()), HttpStatus.OK); + return new ResponseEntity<>( + new PagedList<>(MgmtTargetMapper.toActionStatusRestResponse(statusList.getContent()), + statusList.getTotalElements()), + HttpStatus.OK); } @Override - public ResponseEntity getAssignedDistributionSet(final String targetId) { - final Target findTarget = findTargetWithExceptionIfNotFound(targetId); - final DistributionSetRest distributionSetRest = DistributionSetMapper + public ResponseEntity getAssignedDistributionSet( + @PathVariable("controllerId") final String controllerId) { + final Target findTarget = findTargetWithExceptionIfNotFound(controllerId); + final MgmtDistributionSet distributionSetRest = MgmtDistributionSetMapper .toResponse(findTarget.getAssignedDistributionSet()); final HttpStatus retStatus; if (distributionSetRest == null) { @@ -256,29 +283,30 @@ public class TargetResource implements TargetRestApi { } @Override - public ResponseEntity postAssignedDistributionSet(final String targetId, - final DistributionSetAssigmentRest dsId) { + public ResponseEntity postAssignedDistributionSet(@PathVariable("controllerId") final String controllerId, + @RequestBody final MgmtDistributionSetAssigment dsId) { - findTargetWithExceptionIfNotFound(targetId); - final ActionType type = (dsId.getType() != null) - ? RestResourceConversionHelper.convertActionType(dsId.getType()) : ActionType.FORCED; + findTargetWithExceptionIfNotFound(controllerId); + final ActionType type = (dsId.getType() != null) ? MgmtRestModelMapper.convertActionType(dsId.getType()) + : ActionType.FORCED; final Iterator changed = this.deploymentManagement - .assignDistributionSet(dsId.getId(), type, dsId.getForcetime(), targetId).getAssignedEntity() + .assignDistributionSet(dsId.getId(), type, dsId.getForcetime(), controllerId).getAssignedEntity() .iterator(); if (changed.hasNext()) { return new ResponseEntity<>(HttpStatus.OK); } LOG.error("Target update (ds {} assigment to target {}) failed! Returnd target list is empty.", dsId.getId(), - targetId); + controllerId); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } @Override - public ResponseEntity getInstalledDistributionSet(final String targetId) { - final Target findTarget = findTargetWithExceptionIfNotFound(targetId); - final DistributionSetRest distributionSetRest = DistributionSetMapper + public ResponseEntity getInstalledDistributionSet( + @PathVariable("controllerId") final String controllerId) { + final Target findTarget = findTargetWithExceptionIfNotFound(controllerId); + final MgmtDistributionSet distributionSetRest = MgmtDistributionSetMapper .toResponse(findTarget.getTargetInfo().getInstalledDistributionSet()); final HttpStatus retStatus; if (distributionSetRest == null) { @@ -289,10 +317,10 @@ public class TargetResource implements TargetRestApi { return new ResponseEntity<>(distributionSetRest, retStatus); } - private Target findTargetWithExceptionIfNotFound(final String targetId) { - final Target findTarget = this.targetManagement.findTargetByControllerID(targetId); + private Target findTargetWithExceptionIfNotFound(final String controllerId) { + final Target findTarget = this.targetManagement.findTargetByControllerID(controllerId); if (findTarget == null) { - throw new EntityNotFoundException("Target with Id {" + targetId + "} does not exist"); + throw new EntityNotFoundException("Target with Id {" + controllerId + "} does not exist"); } return findTarget; } @@ -304,4 +332,5 @@ public class TargetResource implements TargetRestApi { } return findAction; } + } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetTagResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTagResource.java similarity index 55% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetTagResource.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTagResource.java index 1a9155828..c765c18cd 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetTagResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTagResource.java @@ -6,26 +6,27 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import java.util.List; import java.util.stream.Collectors; -import org.eclipse.hawkbit.repository.TagFields; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedTargetRequestBody; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut; +import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTargetTagAssigmentResult; +import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.TagManagement; import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult; -import org.eclipse.hawkbit.repository.rsql.RSQLUtility; -import org.eclipse.hawkbit.rest.resource.api.TargetTagRestApi; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.tag.AssignedTargetRequestBody; -import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut; -import org.eclipse.hawkbit.rest.resource.model.tag.TagRest; -import org.eclipse.hawkbit.rest.resource.model.tag.TargetTagAssigmentResultRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -35,16 +36,18 @@ import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** - * REST Resource handling for {@link Tag} CRUD operations. + * REST Resource handling for tag CRUD operations. * */ @RestController -public class TargetTagResource implements TargetTagRestApi { - private static final Logger LOG = LoggerFactory.getLogger(TargetTagResource.class); +public class MgmtTargetTagResource implements MgmtTargetTagRestApi { + private static final Logger LOG = LoggerFactory.getLogger(MgmtTargetTagResource.class); @Autowired private TagManagement tagManagement; @@ -52,9 +55,15 @@ public class TargetTagResource implements TargetTagRestApi { @Autowired private TargetManagement targetManagement; + @Autowired + private EntityFactory entityFactory; + @Override - public ResponseEntity> getTargetTags(final int pagingOffsetParam, final int pagingLimitParam, - final String sortParam, final String rsqlParam) { + public ResponseEntity> getTargetTags( + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -68,46 +77,46 @@ public class TargetTagResource implements TargetTagRestApi { countTargetsAll = this.tagManagement.countTargetTags(); } else { - final Page findTargetPage = this.tagManagement - .findAllTargetTags(RSQLUtility.parse(rsqlParam, TagFields.class), pageable); + final Page findTargetPage = this.tagManagement.findAllTargetTags(rsqlParam, pageable); countTargetsAll = findTargetPage.getTotalElements(); findTargetsAll = findTargetPage; } - final List rest = TagMapper.toResponse(findTargetsAll.getContent()); + final List rest = MgmtTagMapper.toResponse(findTargetsAll.getContent()); return new ResponseEntity<>(new PagedList<>(rest, countTargetsAll), HttpStatus.OK); } @Override - public ResponseEntity getTargetTag(final Long targetTagId) { + public ResponseEntity getTargetTag(@PathVariable("targetTagId") final Long targetTagId) { final TargetTag tag = findTargetTagById(targetTagId); - return new ResponseEntity<>(TagMapper.toResponse(tag), HttpStatus.OK); + return new ResponseEntity<>(MgmtTagMapper.toResponse(tag), HttpStatus.OK); } @Override - public ResponseEntity> createTargetTags(@RequestBody final List tags) { + public ResponseEntity> createTargetTags(@RequestBody final List tags) { LOG.debug("creating {} target tags", tags.size()); final List createdTargetTags = this.tagManagement - .createTargetTags(TagMapper.mapTargeTagFromRequest(tags)); - return new ResponseEntity<>(TagMapper.toResponse(createdTargetTags), HttpStatus.CREATED); + .createTargetTags(MgmtTagMapper.mapTargeTagFromRequest(entityFactory, tags)); + return new ResponseEntity<>(MgmtTagMapper.toResponse(createdTargetTags), HttpStatus.CREATED); } @Override - public ResponseEntity updateTagretTag(final Long targetTagId, final TagRequestBodyPut restTargetTagRest) { + public ResponseEntity updateTagretTag(@PathVariable("targetTagId") final Long targetTagId, + @RequestBody final MgmtTagRequestBodyPut restTargetTagRest) { LOG.debug("update {} target tag", restTargetTagRest); final TargetTag targetTag = findTargetTagById(targetTagId); - TagMapper.updateTag(restTargetTagRest, targetTag); + MgmtTagMapper.updateTag(restTargetTagRest, targetTag); final TargetTag updateTargetTag = this.tagManagement.updateTargetTag(targetTag); LOG.debug("target tag updated"); - return new ResponseEntity<>(TagMapper.toResponse(updateTargetTag), HttpStatus.OK); + return new ResponseEntity<>(MgmtTagMapper.toResponse(updateTargetTag), HttpStatus.OK); } @Override - public ResponseEntity deleteTargetTag(final Long targetTagId) { + public ResponseEntity deleteTargetTag(@PathVariable("targetTagId") final Long targetTagId) { LOG.debug("Delete {} target tag", targetTagId); final TargetTag targetTag = findTargetTagById(targetTagId); @@ -117,39 +126,40 @@ public class TargetTagResource implements TargetTagRestApi { } @Override - public ResponseEntity> getAssignedTargets(final Long targetTagId) { + public ResponseEntity> getAssignedTargets(@PathVariable("targetTagId") final Long targetTagId) { final TargetTag targetTag = findTargetTagById(targetTagId); - return new ResponseEntity<>(TargetMapper.toResponseWithLinksAndPollStatus(targetTag.getAssignedToTargets()), + return new ResponseEntity<>(MgmtTargetMapper.toResponseWithLinksAndPollStatus(targetTag.getAssignedToTargets()), HttpStatus.OK); } @Override - public ResponseEntity toggleTagAssignment(final Long targetTagId, - final List assignedTargetRequestBodies) { + public ResponseEntity toggleTagAssignment( + @PathVariable("targetTagId") final Long targetTagId, + @RequestBody final List assignedTargetRequestBodies) { LOG.debug("Toggle Target assignment {} for target tag {}", assignedTargetRequestBodies.size(), targetTagId); final TargetTag targetTag = findTargetTagById(targetTagId); final TargetTagAssignmentResult assigmentResult = this.targetManagement .toggleTagAssignment(findTargetControllerIds(assignedTargetRequestBodies), targetTag.getName()); - final TargetTagAssigmentResultRest tagAssigmentResultRest = new TargetTagAssigmentResultRest(); - tagAssigmentResultRest.setAssignedTargets(TargetMapper.toResponse(assigmentResult.getAssignedEntity())); - tagAssigmentResultRest.setUnassignedTargets(TargetMapper.toResponse(assigmentResult.getUnassignedEntity())); + final MgmtTargetTagAssigmentResult tagAssigmentResultRest = new MgmtTargetTagAssigmentResult(); + tagAssigmentResultRest.setAssignedTargets(MgmtTargetMapper.toResponse(assigmentResult.getAssignedEntity())); + tagAssigmentResultRest.setUnassignedTargets(MgmtTargetMapper.toResponse(assigmentResult.getUnassignedEntity())); return new ResponseEntity<>(tagAssigmentResultRest, HttpStatus.OK); } @Override - public ResponseEntity> assignTargets(final Long targetTagId, - final List assignedTargetRequestBodies) { + public ResponseEntity> assignTargets(@PathVariable("targetTagId") final Long targetTagId, + @RequestBody final List assignedTargetRequestBodies) { LOG.debug("Assign Targets {} for target tag {}", assignedTargetRequestBodies.size(), targetTagId); final TargetTag targetTag = findTargetTagById(targetTagId); final List assignedTarget = this.targetManagement .assignTag(findTargetControllerIds(assignedTargetRequestBodies), targetTag); - return new ResponseEntity<>(TargetMapper.toResponseWithLinksAndPollStatus(assignedTarget), HttpStatus.OK); + return new ResponseEntity<>(MgmtTargetMapper.toResponseWithLinksAndPollStatus(assignedTarget), HttpStatus.OK); } @Override - public ResponseEntity unassignTargets(final Long targetTagId) { + public ResponseEntity unassignTargets(@PathVariable("targetTagId") final Long targetTagId) { LOG.debug("Unassign all Targets for target tag {}", targetTagId); final TargetTag targetTag = findTargetTagById(targetTagId); if (targetTag.getAssignedToTargets() == null) { @@ -161,7 +171,8 @@ public class TargetTagResource implements TargetTagRestApi { } @Override - public ResponseEntity unassignTarget(final Long targetTagId, final String controllerId) { + public ResponseEntity unassignTarget(@PathVariable("targetTagId") final Long targetTagId, + @PathVariable("controllerId") final String controllerId) { LOG.debug("Unassign target {} for target tag {}", controllerId, targetTagId); final TargetTag targetTag = findTargetTagById(targetTagId); this.targetManagement.unAssignTag(controllerId, targetTag); @@ -176,8 +187,10 @@ public class TargetTagResource implements TargetTagRestApi { return tag; } - private List findTargetControllerIds(final List assignedTargetRequestBodies) { + private List findTargetControllerIds( + final List assignedTargetRequestBodies) { return assignedTargetRequestBodies.stream().map(request -> request.getControllerId()) .collect(Collectors.toList()); } + } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/PagingUtility.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/PagingUtility.java similarity index 91% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/PagingUtility.java rename to hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/PagingUtility.java index ac45796e5..abd9e9ec4 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/PagingUtility.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/PagingUtility.java @@ -6,8 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.ActionFields; import org.eclipse.hawkbit.repository.ActionStatusFields; import org.eclipse.hawkbit.repository.DistributionSetFields; @@ -19,6 +20,7 @@ import org.eclipse.hawkbit.repository.SoftwareModuleFields; import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields; import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields; import org.eclipse.hawkbit.repository.TargetFields; +import org.eclipse.hawkbit.rest.util.SortUtility; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; @@ -35,16 +37,16 @@ public final class PagingUtility { static int sanitizeOffsetParam(final int offset) { if (offset < 0) { - return Integer.parseInt(RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET); + return Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET); } return offset; } static int sanitizePageLimitParam(final int pageLimit) { if (pageLimit < 1) { - return Integer.parseInt(RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT); - } else if (pageLimit > RestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT) { - return RestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT; + return Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT); + } else if (pageLimit > MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT) { + return MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT; } return pageLimit; } diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/DistributionSetResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java similarity index 73% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/DistributionSetResourceTest.java rename to hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java index 6254da992..556454f93 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/DistributionSetResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.fest.assertions.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.equalTo; @@ -26,24 +26,18 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.WithUser; -import org.eclipse.hawkbit.repository.ActionRepository; -import org.eclipse.hawkbit.repository.ControllerManagement; -import org.eclipse.hawkbit.repository.DistributionSetManagement; -import org.eclipse.hawkbit.repository.SoftwareManagement; -import org.eclipse.hawkbit.repository.TargetManagement; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; -import org.eclipse.hawkbit.repository.model.DsMetadataCompositeKey; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; +import org.eclipse.hawkbit.rest.util.JsonBuilder; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -60,15 +54,14 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Management API") @Stories("Distribution Set Resource") -public class DistributionSetResourceTest extends AbstractIntegrationTest { +public class MgmtDistributionSetResourceTest extends AbstractRestIntegrationTest { @Test @Description("This test verifies the call of all Software Modules that are assiged to a Distribution Set through the RESTful API.") public void getSoftwaremodules() throws Exception { // Create DistributionSet with three software modules - final DistributionSet set = TestDataUtil.generateDistributionSet("SMTest", softwareManagement, - distributionSetManagement); - mvc.perform(get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/assignedSM")) + final DistributionSet set = testdataFactory.createDistributionSet("SMTest"); + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/assignedSM")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("$.size", equalTo(set.getModules().size()))); } @@ -78,10 +71,9 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { public void deleteFailureWhenDistributionSetInUse() throws Exception { // create DisSet - final DistributionSet disSet = TestDataUtil.generateDistributionSetWithNoSoftwareModules("Eris", "560a", - distributionSetManagement); - final List smIDs = new ArrayList(); - SoftwareModule sm = new SoftwareModule(osType, "Dysnomia ", "15,772", null, null); + final DistributionSet disSet = testdataFactory.createDistributionSetWithNoSoftwareModules("Eris", "560a"); + final List smIDs = new ArrayList<>(); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "Dysnomia ", "15,772", null, null); sm = softwareManagement.createSoftwareModule(sm); smIDs.add(sm.getId()); final JSONArray smList = new JSONArray(); @@ -89,7 +81,7 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { smList.put(new JSONObject().put("id", Long.valueOf(smID))); } // post assignment - mvc.perform(post(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM") + mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM") .contentType(MediaType.APPLICATION_JSON).content(smList.toString())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); @@ -97,22 +89,23 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final String[] knownTargetIds = new String[] { "1", "2" }; final JSONArray list = new JSONArray(); for (final String targetId : knownTargetIds) { - targetManagement.createTarget(new Target(targetId)); + targetManagement.createTarget(entityFactory.generateTarget(targetId)); list.put(new JSONObject().put("id", Long.valueOf(targetId))); } deploymentManagement.assignDistributionSet(disSet.getId(), knownTargetIds[0]); - mvc.perform(post(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedTargets") - .contentType(MediaType.APPLICATION_JSON).content(list.toString())).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isOk()).andExpect(jsonPath("$.assigned", equalTo(knownTargetIds.length - 1))) + mvc.perform( + post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedTargets") + .contentType(MediaType.APPLICATION_JSON).content(list.toString())) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(jsonPath("$.assigned", equalTo(knownTargetIds.length - 1))) .andExpect(jsonPath("$.alreadyAssigned", equalTo(1))) .andExpect(jsonPath("$.total", equalTo(knownTargetIds.length))); // try to delete the Software Module from DistSet that has been assigned // to the target. - mvc.perform(delete( - RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM/" + smIDs.get(0)) - .contentType(MediaType.APPLICATION_JSON)) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isLocked()) + mvc.perform(delete(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM/" + + smIDs.get(0)).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) + .andExpect(status().isLocked()) .andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.entitiylocked"))); } @@ -121,10 +114,9 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { public void assignmentFailureWhenAssigningToUsedDistributionSet() throws Exception { // create DisSet - final DistributionSet disSet = TestDataUtil.generateDistributionSetWithNoSoftwareModules("Mars", "686,980", - distributionSetManagement); + final DistributionSet disSet = testdataFactory.createDistributionSetWithNoSoftwareModules("Mars", "686,980"); final List smIDs = new ArrayList<>(); - SoftwareModule sm = new SoftwareModule(osType, "Phobos", "0,3189", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "Phobos", "0,3189", null, null); sm = softwareManagement.createSoftwareModule(sm); smIDs.add(sm.getId()); final JSONArray smList = new JSONArray(); @@ -132,7 +124,7 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { smList.put(new JSONObject().put("id", Long.valueOf(smID))); } // post assignment - mvc.perform(post(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM") + mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM") .contentType(MediaType.APPLICATION_JSON).content(smList.toString())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); @@ -140,20 +132,22 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final String[] knownTargetIds = new String[] { "1", "2" }; final JSONArray list = new JSONArray(); for (final String targetId : knownTargetIds) { - targetManagement.createTarget(new Target(targetId)); + targetManagement.createTarget(entityFactory.generateTarget(targetId)); list.put(new JSONObject().put("id", Long.valueOf(targetId))); } // assign DisSet to target and test assignment deploymentManagement.assignDistributionSet(disSet.getId(), knownTargetIds[0]); - mvc.perform(post(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedTargets") - .contentType(MediaType.APPLICATION_JSON).content(list.toString())).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isOk()).andExpect(jsonPath("$.assigned", equalTo(knownTargetIds.length - 1))) + mvc.perform( + post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedTargets") + .contentType(MediaType.APPLICATION_JSON).content(list.toString())) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(jsonPath("$.assigned", equalTo(knownTargetIds.length - 1))) .andExpect(jsonPath("$.alreadyAssigned", equalTo(1))) .andExpect(jsonPath("$.total", equalTo(knownTargetIds.length))); // Create another SM and post assignment - final List smID2s = new ArrayList(); - SoftwareModule sm2 = new SoftwareModule(appType, "Deimos", "1,262", null, null); + final List smID2s = new ArrayList<>(); + SoftwareModule sm2 = entityFactory.generateSoftwareModule(appType, "Deimos", "1,262", null, null); sm2 = softwareManagement.createSoftwareModule(sm2); smID2s.add(sm2.getId()); final JSONArray smList2 = new JSONArray(); @@ -161,7 +155,7 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { smList2.put(new JSONObject().put("id", Long.valueOf(smID))); } - mvc.perform(post(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM") + mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM") .contentType(MediaType.APPLICATION_JSON).content(smList2.toString())) .andDo(MockMvcResultPrinter.print()).andExpect(status().isLocked()) .andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.entitiylocked"))); @@ -172,21 +166,20 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { public void assignSoftwaremoduleToDistributionSet() throws Exception { // create DisSet - final DistributionSet disSet = TestDataUtil.generateDistributionSetWithNoSoftwareModules("Jupiter", "398,88", - distributionSetManagement); + final DistributionSet disSet = testdataFactory.createDistributionSetWithNoSoftwareModules("Jupiter", "398,88"); // Test if size is 0 - mvc.perform(get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM")) + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("$.size", equalTo(disSet.getModules().size()))); // create Software Modules - final List smIDs = new ArrayList(); - SoftwareModule sm = new SoftwareModule(osType, "Europa", "3,551", null, null); + final List smIDs = new ArrayList<>(); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "Europa", "3,551", null, null); sm = softwareManagement.createSoftwareModule(sm); smIDs.add(sm.getId()); - SoftwareModule sm2 = new SoftwareModule(appType, "Ganymed", "7,155", null, null); + SoftwareModule sm2 = entityFactory.generateSoftwareModule(appType, "Ganymed", "7,155", null, null); sm2 = softwareManagement.createSoftwareModule(sm2); smIDs.add(sm2.getId()); - SoftwareModule sm3 = new SoftwareModule(runtimeType, "Kallisto", "16,689", null, null); + SoftwareModule sm3 = entityFactory.generateSoftwareModule(runtimeType, "Kallisto", "16,689", null, null); sm3 = softwareManagement.createSoftwareModule(sm3); smIDs.add(sm3.getId()); final JSONArray list = new JSONArray(); @@ -194,11 +187,11 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { list.put(new JSONObject().put("id", Long.valueOf(smID))); } // post assignment - mvc.perform(post(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM") + mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM") .contentType(MediaType.APPLICATION_JSON).content(list.toString())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); // Test if size is 3 - mvc.perform(get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM")) + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet.getId() + "/assignedSM")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("$.size", equalTo(smIDs.size()))); } @@ -208,19 +201,18 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { public void unassignSoftwaremoduleFromDistributionSet() throws Exception { // Create DistributionSet with three software modules - final DistributionSet set = TestDataUtil.generateDistributionSet("Venus", softwareManagement, - distributionSetManagement); + final DistributionSet set = testdataFactory.createDistributionSet("Venus"); int amountOfSM = set.getModules().size(); - mvc.perform(get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/assignedSM")) + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/assignedSM")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("$.size", equalTo(amountOfSM))); // test the removal of all software modules one by one for (final Iterator iter = set.getModules().iterator(); iter.hasNext();) { final Long smId = iter.next().getId(); mvc.perform(delete( - RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/assignedSM/" + smId)) + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/assignedSM/" + smId)) .andExpect(status().isOk()); - mvc.perform(get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/assignedSM")) + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/assignedSM")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("$.size", equalTo(--amountOfSM))); } @@ -236,14 +228,14 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" }; final JSONArray list = new JSONArray(); for (final String targetId : knownTargetIds) { - targetManagement.createTarget(new Target(targetId)); + targetManagement.createTarget(entityFactory.generateTarget(targetId)); list.put(new JSONObject().put("id", Long.valueOf(targetId))); } // assign already one target to DS deploymentManagement.assignDistributionSet(createdDs.getId(), knownTargetIds[0]); - mvc.perform( - post(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + "/assignedTargets") + mvc.perform(post( + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + "/assignedTargets") .contentType(MediaType.APPLICATION_JSON).content(list.toString())) .andExpect(status().isOk()).andExpect(jsonPath("$.assigned", equalTo(knownTargetIds.length - 1))) .andExpect(jsonPath("$.alreadyAssigned", equalTo(1))) @@ -260,11 +252,11 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final String knownTargetId = "knownTargetId1"; final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); - targetManagement.createTarget(new Target(knownTargetId)); + targetManagement.createTarget(entityFactory.generateTarget(knownTargetId)); deploymentManagement.assignDistributionSet(createdDs.getId(), knownTargetId); - mvc.perform( - get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + "/assignedTargets")) + mvc.perform(get( + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + "/assignedTargets")) .andExpect(status().isOk()).andExpect(jsonPath("$.size", equalTo(1))) .andExpect(jsonPath("$.content[0].controllerId", equalTo(knownTargetId))); } @@ -274,8 +266,8 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { public void getAssignedTargetsOfDistributionSetIsEmpty() throws Exception { final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); - mvc.perform( - get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + "/assignedTargets")) + mvc.perform(get( + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + "/assignedTargets")) .andExpect(status().isOk()).andExpect(jsonPath("$.size", equalTo(0))) .andExpect(jsonPath("$.total", equalTo(0))); } @@ -287,18 +279,18 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final String knownTargetId = "knownTargetId1"; final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); - final Target createTarget = targetManagement.createTarget(new Target(knownTargetId)); + final Target createTarget = targetManagement.createTarget(entityFactory.generateTarget(knownTargetId)); // create some dummy targets which are not assigned or installed - targetManagement.createTarget(new Target("dummy1")); - targetManagement.createTarget(new Target("dummy2")); + targetManagement.createTarget(entityFactory.generateTarget("dummy1")); + targetManagement.createTarget(entityFactory.generateTarget("dummy2")); // assign knownTargetId to distribution set deploymentManagement.assignDistributionSet(createdDs.getId(), knownTargetId); // make it in install state - sendUpdateActionStatusToTargets(controllerManagament, targetManagement, actionRepository, createdDs, - Lists.newArrayList(createTarget), Status.FINISHED, "some message"); + testdataFactory.sendUpdateActionStatusToTargets(Lists.newArrayList(createTarget), Status.FINISHED, + "some message"); - mvc.perform( - get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + "/installedTargets")) + mvc.perform(get( + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + "/installedTargets")) .andExpect(status().isOk()).andExpect(jsonPath("$.size", equalTo(1))) .andExpect(jsonPath("$.content[0].controllerId", equalTo(knownTargetId))); } @@ -308,11 +300,11 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { public void getDistributionSetsWithoutAddtionalRequestParameters() throws Exception { final int sets = 5; createDistributionSetsAlphabetical(sets); - mvc.perform(get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print()) + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(sets))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(sets))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(sets))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(sets))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(sets))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(sets))); } @Test @@ -321,12 +313,12 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final int sets = 5; final int limitSize = 1; createDistributionSetsAlphabetical(sets); - mvc.perform(get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))) + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(sets))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(sets))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize))); } @Test @@ -336,13 +328,13 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final int offsetParam = 2; final int expectedSize = sets - offsetParam; createDistributionSetsAlphabetical(sets); - mvc.perform(get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING) - .param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam)) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(sets))) + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam)) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(sets))) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(sets))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(sets))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize))); } @Test @@ -350,10 +342,10 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { @Description("Ensures that multiple DS requested are listed with expected payload.") public void getDistributionSets() throws Exception { // prepare test data - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(0); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(0); - DistributionSet set = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); + DistributionSet set = testdataFactory.createDistributionSet("one"); set.setRequiredMigrationStep(set.isRequiredMigrationStep()); set = distributionSetManagement.updateDistributionSet(set); @@ -363,7 +355,8 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { // load also lazy stuff set = distributionSetManagement.findDistributionSetByIdWithDetails(set.getId()); - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(1); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(1); // perform request mvc.perform(get("/rest/v1/distributionsets").accept(MediaType.APPLICATION_JSON)) @@ -394,7 +387,7 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Ensures that single DS requested by ID is listed with expected payload.") public void getDistributionSet() throws Exception { - final DistributionSet set = createTestDistributionSet(softwareManagement, distributionSetManagement); + final DistributionSet set = testdataFactory.createUpdatedDistributionSet(); // perform request mvc.perform(get("/rest/v1/distributionsets/{dsId}", set.getId()).accept(MediaType.APPLICATION_JSON)) @@ -426,18 +419,19 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Ensures that multipe DS posted to API are created in the repository.") public void createDistributionSets() throws JSONException, Exception { - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(0); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(0); - final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); - final SoftwareModule jvm = softwareManagement - .createSoftwareModule(new SoftwareModule(runtimeType, "oracle-jre", "1.7.2", null, "")); - final SoftwareModule os = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "poky", "3.0.2", null, "")); + final SoftwareModule ah = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_APP); + final SoftwareModule jvm = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_RT); + final SoftwareModule os = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_OS); - DistributionSet one = TestDataUtil.buildDistributionSet("one", "one", standardDsType, os, jvm, ah); - DistributionSet two = TestDataUtil.buildDistributionSet("two", "two", standardDsType, os, jvm, ah); - DistributionSet three = TestDataUtil.buildDistributionSet("three", "three", standardDsType, os, jvm, ah); + DistributionSet one = testdataFactory.generateDistributionSet("one", "one", standardDsType, + Lists.newArrayList(os, jvm, ah)); + DistributionSet two = testdataFactory.generateDistributionSet("two", "two", standardDsType, + Lists.newArrayList(os, jvm, ah)); + DistributionSet three = testdataFactory.generateDistributionSet("three", "three", standardDsType, + Lists.newArrayList(os, jvm, ah)); three.setRequiredMigrationStep(true); final List sets = new ArrayList<>(); @@ -528,7 +522,8 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { .isEqualTo(String.valueOf(three.getId())); // check in database - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(3); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(3); assertThat(one.isRequiredMigrationStep()).isEqualTo(false); assertThat(two.isRequiredMigrationStep()).isEqualTo(false); assertThat(three.isRequiredMigrationStep()).isEqualTo(true); @@ -542,42 +537,47 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { @Description("Ensures that DS deletion request to API is reflected by the repository.") public void deleteUnassignedistributionSet() throws Exception { // prepare test data - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(0); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(0); - final DistributionSet set = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); + final DistributionSet set = testdataFactory.createDistributionSet("one"); - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(1); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(1); // perform request mvc.perform(delete("/rest/v1/distributionsets/{smId}", set.getId())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); // check repository content - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).isEmpty(); - assertThat(distributionSetRepository.findAll()).isEmpty(); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .isEmpty(); + assertThat(distributionSetManagement.countDistributionSetsAll()).isEqualTo(0); } @Test @Description("Ensures that assigned DS deletion request to API is reflected by the repository by means of deleted flag set.") public void deleteAssignedDistributionSet() throws Exception { // prepare test data - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(0); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(0); - final DistributionSet set = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); - targetManagement.createTarget(new Target("test")); + final DistributionSet set = testdataFactory.createDistributionSet("one"); + targetManagement.createTarget(entityFactory.generateTarget("test")); deploymentManagement.assignDistributionSet(set.getId(), "test"); - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(1); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(1); // perform request mvc.perform(delete("/rest/v1/distributionsets/{smId}", set.getId())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); // check repository content - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(0); - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, true, true)).hasSize(1); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(0); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, true, true)) + .hasSize(1); } @Test @@ -585,14 +585,15 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { public void updateDistributionSet() throws Exception { // prepare test data - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(0); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(0); - final DistributionSet set = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); + final DistributionSet set = testdataFactory.createDistributionSet("one"); - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(1); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(1); - final DistributionSet update = new DistributionSet(); + final DistributionSet update = entityFactory.generateDistributionSet(); update.setVersion("anotherVersion"); update.setName(null); update.setType(standardDsType); @@ -601,18 +602,16 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true).getContent().get(0) - .getVersion()).isEqualTo("anotherVersion"); - assertThat( - distributionSetManagement.findDistributionSetsAll(pageReq, false, true).getContent().get(0).getName()) - .isEqualTo(set.getName()); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true) + .getContent().get(0).getVersion()).isEqualTo("anotherVersion"); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true) + .getContent().get(0).getName()).isEqualTo(set.getName()); } @Test @Description("Ensures that the server reacts properly to invalid requests (URI, Media Type, Methods) with correct reponses.") public void invalidRequestsOnDistributionSetsResource() throws Exception { - final DistributionSet set = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); + final DistributionSet set = testdataFactory.createDistributionSet("one"); final List sets = new ArrayList<>(); sets.add(set); @@ -653,8 +652,7 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { @Test @Description("Ensures that the metadata creation through API is reflected by the repository.") public void createMetadata() throws Exception { - final DistributionSet testDS = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); + final DistributionSet testDS = testdataFactory.createDistributionSet("one"); final String knownKey1 = "knownKey1"; final String knownKey2 = "knownKey2"; @@ -674,10 +672,8 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { .andExpect(jsonPath("[1]key", equalTo(knownKey2))) .andExpect(jsonPath("[1]value", equalTo(knownValue2))); - final DistributionSetMetadata metaKey1 = distributionSetManagement - .findOne(new DsMetadataCompositeKey(testDS, knownKey1)); - final DistributionSetMetadata metaKey2 = distributionSetManagement - .findOne(new DsMetadataCompositeKey(testDS, knownKey2)); + final DistributionSetMetadata metaKey1 = distributionSetManagement.findOne(testDS, knownKey1); + final DistributionSetMetadata metaKey2 = distributionSetManagement.findOne(testDS, knownKey2); assertThat(metaKey1.getValue()).isEqualTo(knownValue1); assertThat(metaKey2.getValue()).isEqualTo(knownValue2); @@ -691,10 +687,9 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final String knownValue = "knownValue"; final String updateValue = "valueForUpdate"; - final DistributionSet testDS = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); - distributionSetManagement - .createDistributionSetMetadata(new DistributionSetMetadata(knownKey, testDS, knownValue)); + final DistributionSet testDS = testdataFactory.createDistributionSet("one"); + distributionSetManagement.createDistributionSetMetadata( + entityFactory.generateDistributionSetMetadata(testDS, knownKey, knownValue)); final JSONObject jsonObject = new JSONObject().put("key", knownKey).put("value", updateValue); @@ -704,8 +699,7 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("key", equalTo(knownKey))).andExpect(jsonPath("value", equalTo(updateValue))); - final DistributionSetMetadata assertDS = distributionSetManagement - .findOne(new DsMetadataCompositeKey(testDS, knownKey)); + final DistributionSetMetadata assertDS = distributionSetManagement.findOne(testDS, knownKey); assertThat(assertDS.getValue()).isEqualTo(updateValue); } @@ -717,16 +711,15 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final String knownKey = "knownKey"; final String knownValue = "knownValue"; - final DistributionSet testDS = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); - distributionSetManagement - .createDistributionSetMetadata(new DistributionSetMetadata(knownKey, testDS, knownValue)); + final DistributionSet testDS = testdataFactory.createDistributionSet("one"); + distributionSetManagement.createDistributionSetMetadata( + entityFactory.generateDistributionSetMetadata(testDS, knownKey, knownValue)); mvc.perform(delete("/rest/v1/distributionsets/{dsId}/metadata/{key}", testDS.getId(), knownKey)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); try { - distributionSetManagement.findOne(new DsMetadataCompositeKey(testDS, knownKey)); + distributionSetManagement.findOne(testDS, knownKey); fail("expected EntityNotFoundException but didn't throw"); } catch (final EntityNotFoundException e) { // ok as expected @@ -739,10 +732,9 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { // prepare and create metadata final String knownKey = "knownKey"; final String knownValue = "knownValue"; - final DistributionSet testDS = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); - distributionSetManagement - .createDistributionSetMetadata(new DistributionSetMetadata(knownKey, testDS, knownValue)); + final DistributionSet testDS = testdataFactory.createDistributionSet("one"); + distributionSetManagement.createDistributionSetMetadata( + entityFactory.generateDistributionSetMetadata(testDS, knownKey, knownValue)); mvc.perform(get("/rest/v1/distributionsets/{dsId}/metadata/{key}", testDS.getId(), knownKey)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) @@ -758,11 +750,11 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final String offsetParam = "0"; final String knownKeyPrefix = "knownKey"; final String knownValuePrefix = "knownValue"; - final DistributionSet testDS = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); + final DistributionSet testDS = testdataFactory.createDistributionSet("one"); for (int index = 0; index < totalMetadata; index++) { - distributionSetManagement.createDistributionSetMetadata(new DistributionSetMetadata(knownKeyPrefix + index, - distributionSetManagement.findDistributionSetById(testDS.getId()), knownValuePrefix + index)); + distributionSetManagement.createDistributionSetMetadata(entityFactory.generateDistributionSetMetadata( + distributionSetManagement.findDistributionSetById(testDS.getId()), knownKeyPrefix + index, + knownValuePrefix + index)); } mvc.perform(get("/rest/v1/distributionsets/{dsId}/metadata?offset=" + offsetParam + "&limit=" + limitParam, @@ -778,9 +770,9 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { public void searchDistributionSetRsql() throws Exception { final String dsSuffix = "test"; final int amount = 10; - TestDataUtil.generateDistributionSets(dsSuffix, amount, softwareManagement, distributionSetManagement); - TestDataUtil.generateDistributionSet("DS1test", softwareManagement, distributionSetManagement); - TestDataUtil.generateDistributionSet("DS2test", softwareManagement, distributionSetManagement); + testdataFactory.createDistributionSets(dsSuffix, amount); + testdataFactory.createDistributionSet("DS1test"); + testdataFactory.createDistributionSet("DS2test"); final String rsqlFindLikeDs1OrDs2 = "name==DS1test,name==DS2test"; @@ -795,9 +787,9 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { @Description("Ensures that a DS search with complete==true parameter returns only DS that are actually completely filled with mandatory modules.") public void filterDistributionSetComplete() throws Exception { final int amount = 10; - TestDataUtil.generateDistributionSets(amount, softwareManagement, distributionSetManagement); - distributionSetManagement.createDistributionSet(new DistributionSet("incomplete", "2", "incomplete", - distributionSetManagement.findDistributionSetTypeByKey("ecl_os"), null)); + testdataFactory.createDistributionSets(amount); + distributionSetManagement.createDistributionSet(entityFactory.generateDistributionSet("incomplete", "2", + "incomplete", distributionSetManagement.findDistributionSetTypeByKey("os"), null)); final String rsqlFindLikeDs1OrDs2 = "complete==" + Boolean.TRUE; @@ -816,7 +808,7 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" }; final JSONArray list = new JSONArray(); for (final String targetId : knownTargetIds) { - targetManagement.createTarget(new Target(targetId)); + targetManagement.createTarget(entityFactory.generateTarget(targetId)); list.put(new JSONObject().put("id", Long.valueOf(targetId))); } @@ -825,9 +817,9 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final String rsqlFindTargetId1 = "controllerId==1"; - mvc.perform( - get(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + "/assignedTargets?q=" - + rsqlFindTargetId1).contentType(MediaType.APPLICATION_JSON).content(list.toString())) + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + + "/assignedTargets?q=" + rsqlFindTargetId1).contentType(MediaType.APPLICATION_JSON) + .content(list.toString())) .andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1))) .andExpect(jsonPath("size", equalTo(1))).andExpect(jsonPath("content[0].controllerId", equalTo("1"))); } @@ -838,11 +830,11 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final int totalMetadata = 10; final String knownKeyPrefix = "knownKey"; final String knownValuePrefix = "knownValue"; - final DistributionSet testDS = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); + final DistributionSet testDS = testdataFactory.createDistributionSet("one"); for (int index = 0; index < totalMetadata; index++) { - distributionSetManagement.createDistributionSetMetadata(new DistributionSetMetadata(knownKeyPrefix + index, - distributionSetManagement.findDistributionSetById(testDS.getId()), knownValuePrefix + index)); + distributionSetManagement.createDistributionSetMetadata(entityFactory.generateDistributionSetMetadata( + distributionSetManagement.findDistributionSetById(testDS.getId()), knownKeyPrefix + index, + knownValuePrefix + index)); } final String rsqlSearchValue1 = "value==knownValue1"; @@ -858,60 +850,10 @@ public class DistributionSetResourceTest extends AbstractIntegrationTest { final Set created = new HashSet<>(); for (int index = 0; index < amount; index++) { final String str = String.valueOf(character); - created.add(TestDataUtil.generateDistributionSet(str, softwareManagement, distributionSetManagement)); + created.add(testdataFactory.createDistributionSet(str)); character++; } return created; } - public static List sendUpdateActionStatusToTargets(final ControllerManagement controllerManagament, - final TargetManagement targetManagement, final ActionRepository actionRepository, final DistributionSet dsA, - final Iterable targs, final Status status, final String... msgs) { - final List result = new ArrayList(); - for (final Target t : targs) { - final List findByTarget = actionRepository.findByTarget(t); - for (final Action action : findByTarget) { - result.add(sendUpdateActionStatusToTarget(controllerManagament, targetManagement, status, action, t, - msgs)); - } - } - return result; - } - - private static Target sendUpdateActionStatusToTarget(final ControllerManagement controllerManagament, - final TargetManagement targetManagement, final Status status, final Action updActA, final Target t, - final String... msgs) { - updActA.setStatus(status); - - final ActionStatus statusMessages = new ActionStatus(); - statusMessages.setAction(updActA); - statusMessages.setOccurredAt(System.currentTimeMillis()); - statusMessages.setStatus(status); - for (final String msg : msgs) { - statusMessages.addMessage(msg); - } - controllerManagament.addUpdateActionStatus(statusMessages, updActA); - return targetManagement.findTargetByControllerID(t.getControllerId()); - } - - public static DistributionSet createTestDistributionSet(final SoftwareManagement softwareManagement, - final DistributionSetManagement distributionSetManagement) { - - DistributionSet set = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); - set.setVersion("anotherVersion"); - set = distributionSetManagement.updateDistributionSet(set); - - set.getModules().forEach(module -> { - module.setDescription("updated description"); - softwareManagement.updateSoftwareModule(module); - }); - - // load also lazy stuff - set = distributionSetManagement.findDistributionSetByIdWithDetails(set.getId()); - - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(1); - return set; - } - } diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResourceTest.java similarity index 83% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeResourceTest.java rename to hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResourceTest.java index 9f3d2a89d..bc6d69cd3 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResourceTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.fest.assertions.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.equalTo; @@ -23,13 +23,14 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.util.ArrayList; import java.util.List; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.WithUser; -import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.test.util.WithUser; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; +import org.eclipse.hawkbit.rest.util.JsonBuilder; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.json.JSONException; import org.json.JSONObject; import org.junit.Test; @@ -44,23 +45,25 @@ import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; /** - * Test for {@link DistributionSetTypeResource}. + * Test for {@link MgmtDistributionSetTypeResource}. * */ @Features("Component Tests - Management API") @Stories("Distribution Set Type Resource") -public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { +public class MgmtDistributionSetTypeResourceTest extends AbstractRestIntegrationTest { @Test @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests.") public void getDistributionSetTypes() throws Exception { - DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123")); + DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123")); testType.setDescription("Desc1234"); testType = distributionSetManagement.updateDistributionSetType(testType); + // 4 types overall (2 hawkbit tenant default, 1 test default and 1 + // generated in this test) mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) @@ -94,14 +97,14 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with sorting by KEY.") public void getDistributionSetTypesSortedByKey() throws Exception { - DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("zzzzz", "TestName123", "Desc123")); + DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("zzzzz", "TestName123", "Desc123")); testType.setDescription("Desc1234"); testType = distributionSetManagement.updateDistributionSetType(testType); // descending mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON) - .param(RestConstants.REQUEST_PARAMETER_SORTING, "KEY:DESC")).andDo(MockMvcResultPrinter.print()) + .param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "KEY:DESC")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$content.[0].id", equalTo(testType.getId().intValue()))) .andExpect(jsonPath("$content.[0].name", equalTo("TestName123"))) @@ -110,11 +113,12 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { .andExpect(jsonPath("$content.[0].createdAt", equalTo(testType.getCreatedAt()))) .andExpect(jsonPath("$content.[0].lastModifiedBy", equalTo("uploadTester"))) .andExpect(jsonPath("$content.[0].lastModifiedAt", equalTo(testType.getLastModifiedAt()))) - .andExpect(jsonPath("$content.[0].key", equalTo("zzzzz"))).andExpect(jsonPath("$total", equalTo(4))); + .andExpect(jsonPath("$content.[0].key", equalTo("zzzzz"))) + .andExpect(jsonPath("$total", equalTo(DEFAULT_DS_TYPES + 1))); // ascending mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON) - .param(RestConstants.REQUEST_PARAMETER_SORTING, "KEY:ASC")).andDo(MockMvcResultPrinter.print()) + .param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "KEY:ASC")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$content.[3].id", equalTo(testType.getId().intValue()))) .andExpect(jsonPath("$content.[3].name", equalTo("TestName123"))) @@ -123,7 +127,8 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { .andExpect(jsonPath("$content.[3].createdAt", equalTo(testType.getCreatedAt()))) .andExpect(jsonPath("$content.[3].lastModifiedBy", equalTo("uploadTester"))) .andExpect(jsonPath("$content.[3].lastModifiedAt", equalTo(testType.getLastModifiedAt()))) - .andExpect(jsonPath("$content.[3].key", equalTo("zzzzz"))).andExpect(jsonPath("$total", equalTo(4))); + .andExpect(jsonPath("$content.[3].key", equalTo("zzzzz"))) + .andExpect(jsonPath("$total", equalTo(DEFAULT_DS_TYPES + 1))); } @Test @@ -131,15 +136,15 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @Description("Checks the correct behaviour of /rest/v1/distributionsettypes POST requests.") public void createDistributionSetTypes() throws JSONException, Exception { - assertThat(distributionSetManagement.countDistributionSetTypesAll()).isEqualTo(3); + assertThat(distributionSetManagement.countDistributionSetTypesAll()).isEqualTo(DEFAULT_DS_TYPES); final List types = new ArrayList<>(); - types.add(new DistributionSetType("test1", "TestName1", "Desc1").addMandatoryModuleType(osType) - .addOptionalModuleType(runtimeType)); - types.add(new DistributionSetType("test2", "TestName2", "Desc2").addOptionalModuleType(osType) - .addOptionalModuleType(runtimeType).addOptionalModuleType(appType)); - types.add(new DistributionSetType("test3", "TestName3", "Desc3").addMandatoryModuleType(osType) - .addMandatoryModuleType(runtimeType)); + types.add(entityFactory.generateDistributionSetType("test1", "TestName1", "Desc1") + .addMandatoryModuleType(osType).addOptionalModuleType(runtimeType)); + types.add(entityFactory.generateDistributionSetType("test2", "TestName2", "Desc2") + .addOptionalModuleType(osType).addOptionalModuleType(runtimeType).addOptionalModuleType(appType)); + types.add(entityFactory.generateDistributionSetType("test3", "TestName3", "Desc3") + .addMandatoryModuleType(osType).addMandatoryModuleType(runtimeType)); final MvcResult mvcResult = mvc .perform(post("/rest/v1/distributionsettypes/").content(JsonBuilder.distributionSetTypes(types)) @@ -203,8 +208,8 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes POST requests.") public void addMandatoryModuleToDistributionSetType() throws JSONException, Exception { - DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123")); + DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123")); assertThat(testType.getOptLockRevision()).isEqualTo(1); mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes", testType.getId()) @@ -222,8 +227,8 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes POST requests.") public void addOptionalModuleToDistributionSetType() throws JSONException, Exception { - DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123")); + DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123")); assertThat(testType.getOptLockRevision()).isEqualTo(1); mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes", testType.getId()) @@ -242,8 +247,8 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes GET requests.") public void getMandatoryModulesOfDistributionSetType() throws JSONException, Exception { - final DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123") + final DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123") .addMandatoryModuleType(osType).addOptionalModuleType(appType)); assertThat(testType.getOptLockRevision()).isEqualTo(1); assertThat(testType.getOptionalModuleTypes()).containsExactly(appType); @@ -261,8 +266,8 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes GET requests.") public void getOptionalModulesOfDistributionSetType() throws JSONException, Exception { - final DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123") + final DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123") .addMandatoryModuleType(osType).addOptionalModuleType(appType)); assertThat(testType.getOptLockRevision()).isEqualTo(1); assertThat(testType.getOptionalModuleTypes()).containsExactly(appType); @@ -273,7 +278,7 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("[0].name", equalTo(appType.getName()))) .andExpect(jsonPath("[0].description", equalTo(appType.getDescription()))) - .andExpect(jsonPath("[0].maxAssignments", equalTo(1))) + .andExpect(jsonPath("[0].maxAssignments", equalTo(Integer.MAX_VALUE))) .andExpect(jsonPath("[0].key", equalTo("application"))); } @@ -281,8 +286,8 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes/{ID} GET requests.") public void getMandatoryModuleOfDistributionSetType() throws JSONException, Exception { - final DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123") + final DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123") .addMandatoryModuleType(osType).addOptionalModuleType(appType)); assertThat(testType.getOptLockRevision()).isEqualTo(1); assertThat(testType.getOptionalModuleTypes()).containsExactly(appType); @@ -303,8 +308,8 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes/{ID} GET requests.") public void getOptionalModuleOfDistributionSetType() throws JSONException, Exception { - final DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123") + final DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123") .addMandatoryModuleType(osType).addOptionalModuleType(appType)); assertThat(testType.getOptLockRevision()).isEqualTo(1); assertThat(testType.getOptionalModuleTypes()).containsExactly(appType); @@ -325,8 +330,8 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes/{ID} DELETE requests.") public void removeMandatoryModuleToDistributionSetType() throws JSONException, Exception { - DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123") + DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123") .addMandatoryModuleType(osType).addOptionalModuleType(appType)); assertThat(testType.getOptLockRevision()).isEqualTo(1); assertThat(testType.getOptionalModuleTypes()).containsExactly(appType); @@ -347,8 +352,8 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes/{ID} DELETE requests.") public void removeOptionalModuleToDistributionSetType() throws JSONException, Exception { - DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123") + DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123") .addMandatoryModuleType(osType).addOptionalModuleType(appType)); assertThat(testType.getOptLockRevision()).isEqualTo(1); assertThat(testType.getOptionalModuleTypes()).containsExactly(appType); @@ -370,8 +375,8 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID} GET requests.") public void getDistributionSetType() throws Exception { - DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123")); + DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123")); testType.setDescription("Desc1234"); testType = distributionSetManagement.updateDistributionSetType(testType); @@ -389,41 +394,41 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/DistributionSetTypes/{ID} DELETE requests (hard delete scenario).") public void deleteDistributionSetTypeUnused() throws Exception { - final DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123")); + final DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123")); - assertThat(distributionSetManagement.countDistributionSetTypesAll()).isEqualTo(4); + assertThat(distributionSetManagement.countDistributionSetTypesAll()).isEqualTo(DEFAULT_DS_TYPES + 1); mvc.perform(delete("/rest/v1/distributionsettypes/{dsId}", testType.getId())) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); - assertThat(distributionSetManagement.countDistributionSetTypesAll()).isEqualTo(3); + assertThat(distributionSetManagement.countDistributionSetTypesAll()).isEqualTo(DEFAULT_DS_TYPES); } @Test @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/DistributionSetTypes/{ID} DELETE requests (soft delete scenario).") public void deleteDistributionSetTypeUsed() throws Exception { - final DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123")); - distributionSetManagement - .createDistributionSet(new DistributionSet("sdfsd", "dsfsdf", "sdfsdf", testType, null)); + final DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123")); + distributionSetManagement.createDistributionSet( + entityFactory.generateDistributionSet("sdfsd", "dsfsdf", "sdfsdf", testType, null)); - assertThat(distributionSetManagement.countDistributionSetTypesAll()).isEqualTo(4); - assertThat(distributionSetTypeRepository.count()).isEqualTo(4); + assertThat(distributionSetManagement.countDistributionSetTypesAll()).isEqualTo(DEFAULT_DS_TYPES + 1); + assertThat(distributionSetManagement.countDistributionSetsAll()).isEqualTo(1); mvc.perform(delete("/rest/v1/distributionsettypes/{smId}", testType.getId())) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); - assertThat(distributionSetTypeRepository.count()).isEqualTo(4); - assertThat(distributionSetManagement.countDistributionSetTypesAll()).isEqualTo(3); + assertThat(distributionSetManagement.countDistributionSetsAll()).isEqualTo(1); + assertThat(distributionSetManagement.countDistributionSetTypesAll()).isEqualTo(DEFAULT_DS_TYPES); } @Test @Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID} PUT requests.") public void updateDistributionSetTypeOnlyDescriptionAndNameUntouched() throws Exception { - final DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123")); + final DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123")); final String body = new JSONObject().put("id", testType.getId()).put("description", "foobardesc") .put("name", "nameShouldNotBeChanged").toString(); @@ -438,50 +443,54 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @Test @Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with paging.") public void getDistributionSetTypesWithoutAddtionalRequestParameters() throws Exception { + + // 3 types overall (2 hawkbit tenant default, 1 test default final int types = 3; - mvc.perform(get(RestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print()) + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(types))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(types))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(types))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(types))); } @Test @Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with paging.") public void getDistributionSetTypesWithPagingLimitRequestParameter() throws Exception { - final int types = 3; + + final int types = DEFAULT_DS_TYPES; final int limitSize = 1; - mvc.perform(get(RestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))) + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize))); } @Test @Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with paging.") public void getDistributionSetTypesWithPagingLimitAndOffsetRequestParameter() throws Exception { - final int types = 3; + + final int types = DEFAULT_DS_TYPES; final int offsetParam = 2; final int expectedSize = types - offsetParam; - mvc.perform(get(RestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING) - .param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam)) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(types))) + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam)) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(types))) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize))); } @Test @Description("Ensures that the server is behaving as expected on invalid requests (wrong media type, wrong ID etc.).") public void invalidRequestsOnDistributionSetTypesResource() throws Exception { - final DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123")); + final DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123")); - final SoftwareModuleType testSmType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test123", "TestName123", "Desc123", 5)); + final SoftwareModuleType testSmType = softwareManagement.createSoftwareModuleType( + entityFactory.generateSoftwareModuleType("test123", "TestName123", "Desc123", 5)); final List types = new ArrayList<>(); types.add(testType); @@ -524,8 +533,10 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { // Modules types at creation time invalid - final DistributionSetType testNewType = new DistributionSetType("test123", "TestName123", "Desc123"); - testNewType.addMandatoryModuleType(new SoftwareModuleType("foo", "bar", "test", Integer.MAX_VALUE)); + final DistributionSetType testNewType = entityFactory.generateDistributionSetType("test123", + "TestName123", "Desc123"); + testNewType.addMandatoryModuleType( + entityFactory.generateSoftwareModuleType("foo", "bar", "test", Integer.MAX_VALUE)); mvc.perform(post("/rest/v1/distributionsettypes") .content(JsonBuilder.distributionSetTypes(Lists.newArrayList(testNewType))) @@ -558,10 +569,10 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { @Test @Description("Search erquest of software module types.") public void searchDistributionSetTypeRsql() throws Exception { - final DistributionSetType testType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test123", "TestName123", "Desc123")); - final DistributionSetType testType2 = distributionSetManagement - .createDistributionSetType(new DistributionSetType("test1234", "TestName1234", "Desc123")); + final DistributionSetType testType = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test123", "TestName123", "Desc123")); + final DistributionSetType testType2 = distributionSetManagement.createDistributionSetType( + entityFactory.generateDistributionSetType("test1234", "TestName1234", "Desc123")); final String rsqlFindLikeDs1OrDs2 = "name==TestName123,name==TestName1234"; @@ -575,7 +586,7 @@ public class DistributionSetTypeResourceTest extends AbstractIntegrationTest { char character = 'a'; for (int index = 0; index < amount; index++) { final String str = String.valueOf(character); - final SoftwareModule softwareModule = new SoftwareModule(osType, str, str, str, str); + final SoftwareModule softwareModule = entityFactory.generateSoftwareModule(osType, str, str, str, str); softwareManagement.createSoftwareModule(softwareModule); character++; diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/DownloadResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResourceTest.java similarity index 63% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/DownloadResourceTest.java rename to hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResourceTest.java index ee0fa52fe..16cc82e75 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/DownloadResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResourceTest.java @@ -6,20 +6,20 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.cache.CacheConstants; import org.eclipse.hawkbit.cache.DownloadArtifactCache; import org.eclipse.hawkbit.cache.DownloadType; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -32,7 +32,7 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Management API") @Stories("Download Resource") -public class DownloadResourceTest extends AbstractIntegrationTestWithMongoDB { +public class MgmtDownloadResourceTest extends AbstractRestIntegrationTestWithMongoDB { @Autowired @Qualifier(CacheConstants.DOWNLOAD_ID_CACHE) @@ -45,11 +45,9 @@ public class DownloadResourceTest extends AbstractIntegrationTestWithMongoDB { @Before public void setupCache() { - final DistributionSet distributionSet = TestDataUtil.generateDistributionSet("Test", softwareManagement, - distributionSetManagement); + final DistributionSet distributionSet = testdataFactory.createDistributionSet("Test"); final SoftwareModule softwareModule = distributionSet.getModules().stream().findFirst().get(); - final Artifact artifact = TestDataUtil.generateArtifacts(artifactManagement, softwareModule.getId()).stream() - .findFirst().get(); + final Artifact artifact = testdataFactory.createLocalArtifacts(softwareModule.getId()).stream().findFirst().get(); downloadIdCache.put(downloadIdSha1, new DownloadArtifactCache(DownloadType.BY_SHA1, artifact.getSha1Hash())); } @@ -57,9 +55,8 @@ public class DownloadResourceTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("This test verifies the call of download artifact without a valid download id fails.") public void testNoDownloadIdAvailable() throws Exception { - mvc.perform( - get(RestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + RestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, - downloadIdNotAvailable)) + mvc.perform(get(MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, downloadIdNotAvailable)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound()); } @@ -67,16 +64,14 @@ public class DownloadResourceTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("This test verifies the call of download artifact works and the download id will be removed.") public void testDownload() throws Exception { - mvc.perform( - get(RestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + RestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, - downloadIdSha1)) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); + mvc.perform(get(MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, downloadIdSha1)).andDo(MockMvcResultPrinter.print()) + .andExpect(status().isOk()); // because cache is empty - mvc.perform( - get(RestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + RestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, - downloadIdSha1)) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound()); + mvc.perform(get(MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, downloadIdSha1)).andDo(MockMvcResultPrinter.print()) + .andExpect(status().isNotFound()); } diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/RolloutResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java similarity index 81% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/RolloutResourceTest.java rename to hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java index f27eb5186..11536e6e1 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/RolloutResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.fest.assertions.api.Assertions.assertThat; import static org.hamcrest.Matchers.equalTo; @@ -21,19 +21,21 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.util.List; import java.util.concurrent.Callable; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.WithUser; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.RolloutGroupManagement; import org.eclipse.hawkbit.repository.RolloutManagement; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupConditionBuilder; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; +import org.eclipse.hawkbit.repository.test.util.WithUser; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; +import org.eclipse.hawkbit.rest.util.JsonBuilder; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; +import org.eclipse.hawkbit.rest.util.SuccessCondition; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Description; @@ -45,11 +47,11 @@ import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; /** - * Tests for covering the {@link RolloutResource}. + * Tests for covering the {@link MgmtRolloutResource}. */ @Features("Component Tests - Management API") @Stories("Rollout Resource") -public class RolloutResourceTest extends AbstractIntegrationTest { +public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest { @Autowired private RolloutManagement rolloutManagement; @@ -70,8 +72,7 @@ public class RolloutResourceTest extends AbstractIntegrationTest { @Description("Testing that creating rollout with insufficient permission returns forbidden") @WithUser(allSpPermissions = true, removeFromAllPermission = "ROLLOUT_MANAGEMENT") public void createRolloutWithInsufficientPermissionReturnsForbidden() throws Exception { - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); mvc.perform(post("/rest/v1/rollouts") .content(JsonBuilder.rollout("name", "desc", 10, dsA.getId(), "name==test", null)) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) @@ -89,8 +90,7 @@ public class RolloutResourceTest extends AbstractIntegrationTest { @Test @Description("Testing that creating rollout with not valid formed target filter query returns bad request") public void createRolloutWithNotWellFormedFilterReturnsBadRequest() throws Exception { - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); mvc.perform(post("/rest/v1/rollouts") .content(JsonBuilder.rollout("name", "desc", 10, dsA.getId(), "name=test", null)) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) @@ -104,8 +104,7 @@ public class RolloutResourceTest extends AbstractIntegrationTest { final String targetFilterQuery = null; - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); mvc.perform(post("/rest/v1/rollouts") .content(JsonBuilder.rollout("rollout1", "desc", 10, dsA.getId(), targetFilterQuery, null)) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) @@ -118,8 +117,7 @@ public class RolloutResourceTest extends AbstractIntegrationTest { @Test @Description("Testing that rollout can be created") public void createRollout() throws Exception { - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); postRollout("rollout1", 10, dsA.getId(), "name==target1"); } @@ -134,8 +132,7 @@ public class RolloutResourceTest extends AbstractIntegrationTest { @Test @Description("Testing that rollout paged list contains rollouts") public void rolloutPagedListContainsAllRollouts() throws Exception { - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // setup - create 2 rollouts postRollout("rollout1", 10, dsA.getId(), "name==target1"); postRollout("rollout2", 5, dsA.getId(), "name==target2"); @@ -156,8 +153,7 @@ public class RolloutResourceTest extends AbstractIntegrationTest { @Test @Description("Testing that rollout paged list is limited by the query param limit") public void rolloutPagedListIsLimitedToQueryParam() throws Exception { - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // setup - create 2 rollouts postRollout("rollout1", 10, dsA.getId(), "name==target1"); postRollout("rollout2", 5, dsA.getId(), "name==target2"); @@ -172,9 +168,8 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void retrieveRolloutGroupsForSpecificRollout() throws Exception { // setup final int amountTargets = 20; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); @@ -195,9 +190,8 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void startingRolloutSwitchesIntoRunningState() throws Exception { // setup final int amountTargets = 20; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); @@ -218,9 +212,8 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void pausingRolloutSwitchesIntoPausedState() throws Exception { // setup final int amountTargets = 20; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); @@ -245,9 +238,8 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void resumingRolloutSwitchesIntoRunningState() throws Exception { // setup final int amountTargets = 20; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); @@ -276,9 +268,8 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void startingAlreadyStartedRolloutReturnsBadRequest() throws Exception { // setup final int amountTargets = 20; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); @@ -298,9 +289,8 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void resumingNotStartedRolloutReturnsBadRequest() throws Exception { // setup final int amountTargets = 20; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); @@ -316,9 +306,8 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void startingRolloutFirstRolloutGroupIsInRunningState() throws Exception { // setup final int amountTargets = 10; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*"); @@ -342,9 +331,8 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void retrieveSingleRolloutGroup() throws Exception { // setup final int amountTargets = 10; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); @@ -366,9 +354,8 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void retrieveTargetsFromRolloutGroup() throws Exception { // setup final int amountTargets = 10; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*"); @@ -390,9 +377,8 @@ public class RolloutResourceTest extends AbstractIntegrationTest { // setup final int amountTargets = 10; final List targets = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + .createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*"); @@ -415,9 +401,8 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void retrieveTargetsFromRolloutGroupAfterRolloutIsStarted() throws Exception { // setup final int amountTargets = 10; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*"); @@ -440,16 +425,15 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void startingRolloutSwitchesIntoRunningStateAsync() throws Exception { final int amountTargets = 1000; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); // starting rollout mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId()) - .param(RestConstants.REQUEST_PARAMETER_ASYNC, "true")).andDo(MockMvcResultPrinter.print()) + .param(MgmtRestConstants.REQUEST_PARAMETER_ASYNC, "true")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); // check if running @@ -465,30 +449,32 @@ public class RolloutResourceTest extends AbstractIntegrationTest { final int amountTargetsRollout2 = 25; final int amountTargetsRollout3 = 25; final int amountTargetsOther = 25; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargetsRollout1, "rollout1", "rollout1")); - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargetsRollout2, "rollout2", "rollout2")); - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargetsRollout3, "rollout3", "rollout3")); - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargetsOther, "other1", "other1")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement + .createTargets(testdataFactory.generateTargets(amountTargetsRollout1, "rollout1", "rollout1")); + targetManagement + .createTargets(testdataFactory.generateTargets(amountTargetsRollout2, "rollout2", "rollout2")); + targetManagement + .createTargets(testdataFactory.generateTargets(amountTargetsRollout3, "rollout3", "rollout3")); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargetsOther, "other1", "other1")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); createRollout("rollout1", 5, dsA.getId(), "controllerId==rollout1*"); final Rollout rollout2 = createRollout("rollout2", 5, dsA.getId(), "controllerId==rollout2*"); createRollout("rollout3", 5, dsA.getId(), "controllerId==rollout3*"); createRollout("other1", 5, dsA.getId(), "controllerId==other1*"); - mvc.perform(get("/rest/v1/rollouts").param(RestConstants.REQUEST_PARAMETER_SEARCH, "name==*2")) + mvc.perform(get("/rest/v1/rollouts").param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==*2")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$content", hasSize(1))).andExpect(jsonPath("$total", equalTo(1))) .andExpect(jsonPath("$content[0].name", equalTo(rollout2.getName()))); - mvc.perform(get("/rest/v1/rollouts").param(RestConstants.REQUEST_PARAMETER_SEARCH, "name==rollout*")) + mvc.perform(get("/rest/v1/rollouts").param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==rollout*")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$content", hasSize(3))).andExpect(jsonPath("$total", equalTo(3))); - mvc.perform(get("/rest/v1/rollouts").param(RestConstants.REQUEST_PARAMETER_SEARCH, "name==*1")) + mvc.perform(get("/rest/v1/rollouts").param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==*1")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$content", hasSize(2))).andExpect(jsonPath("$total", equalTo(2))); @@ -500,27 +486,26 @@ public class RolloutResourceTest extends AbstractIntegrationTest { public void retrieveRolloutGroupsForSpecificRolloutWithRSQLParam() throws Exception { // setup final int amountTargets = 20; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); // create rollout including the created targets with prefix 'rollout' final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); // retrieve rollout groups from created rollout mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId()) - .param(RestConstants.REQUEST_PARAMETER_SEARCH, "name==group-1")).andDo(MockMvcResultPrinter.print()) + .param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group-1")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$content", hasSize(1))).andExpect(jsonPath("$total", equalTo(1))) .andExpect(jsonPath("$content[0].name", equalTo("group-1"))); mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId()) - .param(RestConstants.REQUEST_PARAMETER_SEARCH, "name==group*")).andDo(MockMvcResultPrinter.print()) + .param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group*")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$content", hasSize(4))).andExpect(jsonPath("$total", equalTo(4))); mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId()) - .param(RestConstants.REQUEST_PARAMETER_SEARCH, "name==group-1,name==group-2")) + .param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group-1,name==group-2")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$content", hasSize(2))).andExpect(jsonPath("$total", equalTo(2))); @@ -574,7 +559,7 @@ public class RolloutResourceTest extends AbstractIntegrationTest { private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId, final String targetFilterQuery) { - final Rollout rollout = new Rollout(); + final Rollout rollout = entityFactory.generateRollout(); rollout.setDistributionSet(distributionSetManagement.findDistributionSetById(distributionSetId)); rollout.setName(name); rollout.setTargetFilterQuery(targetFilterQuery); diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java similarity index 86% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleResourceTest.java rename to hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java index 1d2222c9a..79a3fc2b2 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.fest.assertions.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.equalTo; @@ -32,21 +32,21 @@ import java.util.List; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomStringUtils; -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; -import org.eclipse.hawkbit.HashGeneratorUtils; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.WithUser; import org.eclipse.hawkbit.exception.SpServerError; +import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.model.SwMetadataCompositeKey; -import org.eclipse.hawkbit.rest.resource.model.ExceptionInfo; -import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactRest; +import org.eclipse.hawkbit.repository.test.util.HashGeneratorUtils; +import org.eclipse.hawkbit.repository.test.util.WithUser; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB; +import org.eclipse.hawkbit.rest.json.model.ExceptionInfo; +import org.eclipse.hawkbit.rest.util.JsonBuilder; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -64,18 +64,17 @@ import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; /** - * Tests for {@link SoftwareModuleResource} {@link RestController}. + * Tests for {@link MgmtSoftwareModuleResource} {@link RestController}. * */ @Features("Component Tests - Management API") @Stories("Software Module Resource") -public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongoDB { +public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestWithMongoDB { @Before public void assertPreparationOfRepo() { assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).as("no softwaremodule should be founded") .hasSize(0); - assertThat(artifactRepository.findAll()).as("no artifacts should be founded").hasSize(0); } @Test @@ -90,11 +89,15 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo final String updateVendor = "newVendor1"; final String updateDescription = "newDescription1"; - softwareManagement.createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); - softwareManagement.createSoftwareModule(new SoftwareModule(runtimeType, "oracle-jre", "1.7.2", null, "")); - softwareManagement.createSoftwareModule(new SoftwareModule(osType, "poky", "3.0.2", null, "")); + softwareManagement.createSoftwareModule( + entityFactory.generateSoftwareModule(appType, "agent-hub", "1.0.1", null, "")); + softwareManagement.createSoftwareModule( + entityFactory.generateSoftwareModule(runtimeType, "oracle-jre", "1.7.2", null, "")); + softwareManagement + .createSoftwareModule(entityFactory.generateSoftwareModule(osType, "poky", "3.0.2", null, "")); - SoftwareModule sm = new SoftwareModule(osType, knownSWName, knownSWVersion, knownSWDescription, knownSWVendor); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, knownSWName, knownSWVersion, + knownSWDescription, knownSWVendor); sm = softwareManagement.createSoftwareModule(sm); assertThat(sm.getName()).as("Wrong name of the software module").isEqualTo(knownSWName); @@ -120,9 +123,8 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @Test @Description("Tests the uppload of an artifact binary. The upload is executed and the content checked in the repository for completenes.") public void uploadArtifact() throws Exception { - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); - assertThat(artifactRepository.findAll()).hasSize(0); // create test file final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); @@ -142,7 +144,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo .andExpect(jsonPath("$providedFilename", equalTo("origFilename"))).andReturn(); // check rest of response compared to DB - final ArtifactRest artResult = ResourceUtility + final MgmtArtifact artResult = ResourceUtility .convertArtifactResponse(mvcResult.getResponse().getContentAsString()); final Long artId = ((LocalArtifact) softwareManagement.findSoftwareModuleWithDetails(sm.getId()).getArtifacts() .get(0)).getId(); @@ -161,7 +163,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo private void assertArtifact(final SoftwareModule sm, final byte[] random) throws IOException { // check result in db... // repo - assertThat(artifactRepository.findAll()).as("Wrong artifact size").hasSize(1); + assertThat(artifactManagement.countLocalArtifactsAll()).as("Wrong artifact size").isEqualTo(1); // binary assertTrue("Wrong artifact content", @@ -187,9 +189,9 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @Description("Verfies that the system does not accept empty artifact uploads. Expected response: BAD REQUEST") public void emptyUploadArtifact() throws Exception { assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0); - assertThat(artifactRepository.findAll()).hasSize(0); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(0); - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); final MockMultipartFile file = new MockMultipartFile("file", "orig", null, new byte[0]); @@ -202,7 +204,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @Test @Description("Verfies that the system does not accept identical artifacts uploads for the same software module. Expected response: CONFLICT") public void duplicateUploadArtifact() throws Exception { - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); @@ -224,9 +226,9 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @Test @Description("verfies that option to upload artifacts with a custom defined by metadata, i.e. not the file name of the binary itself.") public void uploadArtifactWithCustomName() throws Exception { - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); - assertThat(artifactRepository.findAll()).hasSize(0); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(0); // create test file final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); @@ -241,7 +243,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo // check result in db... // repo - assertThat(artifactRepository.findAll()).as("Artifact size is wring").hasSize(1); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(1); // hashes assertThat(artifactManagement.findLocalArtifactByFilename("customFilename")).as("Local artifact is wrong") @@ -251,9 +253,9 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @Test @Description("Verfies that the system refuses upload of an artifact where the provided hash sums do not match. Expected result: BAD REQUEST") public void uploadArtifactWithHashCheck() throws Exception { - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); - assertThat(artifactRepository.findAll()).hasSize(0); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(0); // create test file final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); @@ -295,7 +297,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @Test @Description("Tests binary download of an artifact including verfication that the downloaded binary is consistent and that the etag header is as expected identical to the SHA1 hash of the file.") public void downloadArtifact() throws Exception { - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); @@ -323,14 +325,14 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo Arrays.equals(result2.getResponse().getContentAsByteArray(), random)); assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).as("Softwaremodule size is wrong").hasSize(1); - assertThat(artifactRepository.findAll()).as("Wrong artifact repostiory").hasSize(2); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(2); } @Test @Description("Verifies the listing of one defined artifact assigned to a given software module. That includes the artifact metadata and download links.") public void getArtifact() throws Exception { // prepare data for test - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); @@ -356,7 +358,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @Test @Description("Verifies the listing of all artifacts assigned to a software module. That includes the artifact metadata and download links.") public void getArtifacts() throws Exception { - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); @@ -399,7 +401,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); final MockMultipartFile file = new MockMultipartFile("file", "orig", null, random); - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); // no artifact available @@ -432,7 +434,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @Test @Description("Verfies that the system refuses unsupported request types and answers as defined to them, e.g. NOT FOUND on a non existing resource. Or a HTTP POST for updating a resource results in METHOD NOT ALLOWED etc.") public void invalidRequestsOnSoftwaremodulesResource() throws Exception { - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); final List modules = new ArrayList<>(); @@ -473,11 +475,11 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo public void getSoftwareModulesWithoutAddtionalRequestParameters() throws Exception { final int modules = 5; createSoftwareModulesAlphabetical(modules); - mvc.perform(get(RestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print()) + mvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(modules))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(modules))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(modules))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(modules))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(modules))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(modules))); } @Test @@ -486,12 +488,12 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo final int modules = 5; final int limitSize = 1; createSoftwareModulesAlphabetical(modules); - mvc.perform(get(RestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))) + mvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(modules))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(modules))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize))); } @Test @@ -501,26 +503,29 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo final int offsetParam = 2; final int expectedSize = modules - offsetParam; createSoftwareModulesAlphabetical(modules); - mvc.perform(get(RestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) - .param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam)) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(modules))) + mvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam)) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(modules))) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(modules))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(modules))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize))); } @Test @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Test retrieval of all software modules the user has access to.") public void getSoftwareModules() throws Exception { - SoftwareModule os = new SoftwareModule(osType, "name1", "version1", "description1", "vendor1"); + SoftwareModule os = entityFactory.generateSoftwareModule(osType, "name1", "version1", "description1", + "vendor1"); os = softwareManagement.createSoftwareModule(os); - SoftwareModule jvm = new SoftwareModule(runtimeType, "name1", "version1", "description1", "vendor1"); + SoftwareModule jvm = entityFactory.generateSoftwareModule(runtimeType, "name1", "version1", "description1", + "vendor1"); jvm = softwareManagement.createSoftwareModule(jvm); - SoftwareModule ah = new SoftwareModule(appType, "name1", "version1", "description1", "vendor1"); + SoftwareModule ah = entityFactory.generateSoftwareModule(appType, "name1", "version1", "description1", + "vendor1"); ah = softwareManagement.createSoftwareModule(ah); mvc.perform(get("/rest/v1/softwaremodules").accept(MediaType.APPLICATION_JSON)) @@ -582,22 +587,28 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @Test @Description("Test the various filter parameters, e.g. filter by name or type of the module.") public void getSoftwareModulesWithFilterParameters() throws Exception { - SoftwareModule os1 = new SoftwareModule(osType, "osName1", "1.0.0", "description1", "vendor1"); + SoftwareModule os1 = entityFactory.generateSoftwareModule(osType, "osName1", "1.0.0", "description1", + "vendor1"); os1 = softwareManagement.createSoftwareModule(os1); - SoftwareModule jvm1 = new SoftwareModule(runtimeType, "runtimeName1", "2.0.0", "description1", "vendor1"); + SoftwareModule jvm1 = entityFactory.generateSoftwareModule(runtimeType, "runtimeName1", "2.0.0", + "description1", "vendor1"); jvm1 = softwareManagement.createSoftwareModule(jvm1); - SoftwareModule ah1 = new SoftwareModule(appType, "appName1", "3.0.0", "description1", "vendor1"); + SoftwareModule ah1 = entityFactory.generateSoftwareModule(appType, "appName1", "3.0.0", "description1", + "vendor1"); ah1 = softwareManagement.createSoftwareModule(ah1); - SoftwareModule os2 = new SoftwareModule(osType, "osName2", "1.0.1", "description2", "vendor2"); + SoftwareModule os2 = entityFactory.generateSoftwareModule(osType, "osName2", "1.0.1", "description2", + "vendor2"); os2 = softwareManagement.createSoftwareModule(os2); - SoftwareModule jvm2 = new SoftwareModule(runtimeType, "runtimeName2", "2.0.1", "description2", "vendor2"); + SoftwareModule jvm2 = entityFactory.generateSoftwareModule(runtimeType, "runtimeName2", "2.0.1", + "description2", "vendor2"); jvm2 = softwareManagement.createSoftwareModule(jvm2); - SoftwareModule ah2 = new SoftwareModule(appType, "appName2", "3.0.1", "description2", "vendor2"); + SoftwareModule ah2 = entityFactory.generateSoftwareModule(appType, "appName2", "3.0.1", "description2", + "vendor2"); ah2 = softwareManagement.createSoftwareModule(ah2); assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(6); @@ -674,7 +685,8 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Tests GET request on /rest/v1/softwaremodules/{smId}.") public void getSoftareModule() throws Exception { - SoftwareModule os = new SoftwareModule(osType, "name1", "version1", "description1", "vendor1"); + SoftwareModule os = entityFactory.generateSoftwareModule(osType, "name1", "version1", "description1", + "vendor1"); os = softwareManagement.createSoftwareModule(os); mvc.perform(get("/rest/v1/softwaremodules/{smId}", os.getId()).accept(MediaType.APPLICATION_JSON)) @@ -693,7 +705,8 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo .andExpect(jsonPath("$_links.artifacts.href", equalTo("http://localhost/rest/v1/softwaremodules/" + os.getId() + "/artifacts"))); - SoftwareModule jvm = new SoftwareModule(runtimeType, "name1", "version1", "description1", "vendor1"); + SoftwareModule jvm = entityFactory.generateSoftwareModule(runtimeType, "name1", "version1", "description1", + "vendor1"); jvm = softwareManagement.createSoftwareModule(jvm); mvc.perform(get("/rest/v1/softwaremodules/{smId}", jvm.getId()).accept(MediaType.APPLICATION_JSON)) @@ -712,7 +725,8 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo .andExpect(jsonPath("$_links.artifacts.href", equalTo("http://localhost/rest/v1/softwaremodules/" + jvm.getId() + "/artifacts"))); - SoftwareModule ah = new SoftwareModule(appType, "name1", "version1", "description1", "vendor1"); + SoftwareModule ah = entityFactory.generateSoftwareModule(appType, "name1", "version1", "description1", + "vendor1"); ah = softwareManagement.createSoftwareModule(ah); mvc.perform(get("/rest/v1/softwaremodules/{smId}", ah.getId()).accept(MediaType.APPLICATION_JSON)) @@ -738,9 +752,12 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Verfies that the create request actually results in the creation of the modules in the repository.") public void createSoftwareModules() throws JSONException, Exception { - final SoftwareModule os = new SoftwareModule(osType, "name1", "version1", "description1", "vendor1"); - final SoftwareModule jvm = new SoftwareModule(runtimeType, "name2", "version1", "description1", "vendor1"); - final SoftwareModule ah = new SoftwareModule(appType, "name3", "version1", "description1", "vendor1"); + final SoftwareModule os = entityFactory.generateSoftwareModule(osType, "name1", "version1", "description1", + "vendor1"); + final SoftwareModule jvm = entityFactory.generateSoftwareModule(runtimeType, "name2", "version1", + "description1", "vendor1"); + final SoftwareModule ah = entityFactory.generateSoftwareModule(appType, "name3", "version1", + "description1", "vendor1"); final List modules = new ArrayList<>(); modules.add(os); @@ -821,7 +838,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo @Description("Verifies successfull deletion of software modules that are not in use, i.e. assigned to a DS.") public void deleteUnassignedSoftwareModule() throws Exception { - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); @@ -829,24 +846,20 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), sm.getId(), "file1", false); assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).as("Softwaremoudle size is wrong").hasSize(1); - assertThat(artifactRepository.findAll()).as("artifact site is wrong").hasSize(1); - assertThat(softwareModuleRepository.findAll()).as("Softwaremoudle size is wrong").hasSize(1); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(1); mvc.perform(delete("/rest/v1/softwaremodules/{smId}", sm.getId())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); assertThat(softwareManagement.findSoftwareModulesAll(pageReq)) .as("After delete no softwarmodule should be available").isEmpty(); - assertThat(softwareModuleRepository.findAll()).as("After delete no softwarmodule should be available") - .isEmpty(); - assertThat(artifactRepository.findAll()).as("After delete no artifact should be available").isEmpty(); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(0); } @Test @Description("Verifies successfull deletion of software modules that are in use, i.e. assigned to a DS which should result in movinf the module to the archive.") public void deleteAssignedSoftwareModule() throws Exception { - final DistributionSet ds1 = TestDataUtil.generateDistributionSet("a", softwareManagement, - distributionSetManagement); + final DistributionSet ds1 = testdataFactory.createDistributionSet("a"); final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); @@ -854,8 +867,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo ds1.findFirstModuleByType(appType).getId(), "file1", false); assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(3); - assertThat(artifactRepository.findAll()).hasSize(1); - assertThat(softwareModuleRepository.findAll()).hasSize(3); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(1); mvc.perform(delete("/rest/v1/softwaremodules/{smId}", ds1.findFirstModuleByType(appType).getId())) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); @@ -867,17 +879,14 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo // all 3 are now marked as deleted assertThat(softwareManagement.findSoftwareModulesAll(pageReq).getNumber()) .as("After delete no softwarmodule should be available").isEqualTo(0); - assertThat(softwareModuleRepository.findAll()).as("After delete no softwarmodule should marked as deleted") - .hasSize(3); - assertThat(artifactRepository.findAll()).as("After delete artifact should available for marked as deleted sm's") - .hasSize(1); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(1); } @Test @Description("Tests the deletion of an artifact including verfication that the artifact is actually erased in the repository and removed from the software module.") public void deleteArtifact() throws Exception { // Create 1 SM - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); @@ -891,7 +900,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(1); assertThat(softwareManagement.findSoftwareModuleWithDetails(sm.getId()).getArtifacts()).hasSize(2); - assertThat(artifactRepository.findAll()).hasSize(2); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(2); // delete mvc.perform(delete("/rest/v1/softwaremodules/{smId}/artifacts/{artId}", sm.getId(), artifact.getId())) @@ -900,8 +909,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo // check that only one artifact is still alive and still assigned assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).as("After the sm should be marked as deleted") .hasSize(1); - assertThat(artifactRepository.findAll()).as("After delete artifact should available for marked as deleted sm's") - .hasSize(1); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(1); assertThat(softwareManagement.findSoftwareModuleWithDetails(sm.getId()).getArtifacts()) .as("After delete artifact should available for marked as deleted sm's").hasSize(1); @@ -916,8 +924,8 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo final String knownKey2 = "knownKey1"; final String knownValue2 = "knownValue1"; - final SoftwareModule sm = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "name 1", "version 1", null, null)); + final SoftwareModule sm = softwareManagement.createSoftwareModule( + entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null)); final JSONArray jsonArray = new JSONArray(); jsonArray.put(new JSONObject().put("key", knownKey1).put("value", knownValue1)); @@ -930,10 +938,8 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo .andExpect(jsonPath("[1]key", equalTo(knownKey2))) .andExpect(jsonPath("[1]value", equalTo(knownValue2))); - final SoftwareModuleMetadata metaKey1 = softwareManagement - .findSoftwareModuleMetadata(new SwMetadataCompositeKey(sm, knownKey1)); - final SoftwareModuleMetadata metaKey2 = softwareManagement - .findSoftwareModuleMetadata(new SwMetadataCompositeKey(sm, knownKey2)); + final SoftwareModuleMetadata metaKey1 = softwareManagement.findSoftwareModuleMetadata(sm, knownKey1); + final SoftwareModuleMetadata metaKey2 = softwareManagement.findSoftwareModuleMetadata(sm, knownKey2); assertThat(metaKey1.getValue()).as("Metadata key is wrong").isEqualTo(knownValue1); assertThat(metaKey2.getValue()).as("Metadata key is wrong").isEqualTo(knownValue2); @@ -947,9 +953,10 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo final String knownValue = "knownValue"; final String updateValue = "valueForUpdate"; - final SoftwareModule sm = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "name 1", "version 1", null, null)); - softwareManagement.createSoftwareModuleMetadata(new SoftwareModuleMetadata(knownKey, sm, knownValue)); + final SoftwareModule sm = softwareManagement.createSoftwareModule( + entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null)); + softwareManagement.createSoftwareModuleMetadata( + entityFactory.generateSoftwareModuleMetadata(sm, knownKey, knownValue)); final JSONObject jsonObject = new JSONObject().put("key", knownKey).put("value", updateValue); @@ -959,8 +966,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("key", equalTo(knownKey))).andExpect(jsonPath("value", equalTo(updateValue))); - final SoftwareModuleMetadata assertDS = softwareManagement - .findSoftwareModuleMetadata(new SwMetadataCompositeKey(sm, knownKey)); + final SoftwareModuleMetadata assertDS = softwareManagement.findSoftwareModuleMetadata(sm, knownKey); assertThat(assertDS.getValue()).as("Metadata is wrong").isEqualTo(updateValue); } @@ -971,15 +977,16 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo final String knownKey = "knownKey"; final String knownValue = "knownValue"; - final SoftwareModule sm = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "name 1", "version 1", null, null)); - softwareManagement.createSoftwareModuleMetadata(new SoftwareModuleMetadata(knownKey, sm, knownValue)); + final SoftwareModule sm = softwareManagement.createSoftwareModule( + entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null)); + softwareManagement.createSoftwareModuleMetadata( + entityFactory.generateSoftwareModuleMetadata(sm, knownKey, knownValue)); mvc.perform(delete("/rest/v1/softwaremodules/{swId}/metadata/{key}", sm.getId(), knownKey)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); try { - softwareManagement.findSoftwareModuleMetadata(new SwMetadataCompositeKey(sm, knownKey)); + softwareManagement.findSoftwareModuleMetadata(sm, knownKey); fail("expected EntityNotFoundException but didn't throw"); } catch (final EntityNotFoundException e) { // ok as expected @@ -992,12 +999,13 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo final int totalMetadata = 10; final String knownKeyPrefix = "knownKey"; final String knownValuePrefix = "knownValue"; - final SoftwareModule sm = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "name 1", "version 1", null, null)); + final SoftwareModule sm = softwareManagement.createSoftwareModule( + entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null)); for (int index = 0; index < totalMetadata; index++) { - softwareManagement.createSoftwareModuleMetadata(new SoftwareModuleMetadata(knownKeyPrefix + index, - softwareManagement.findSoftwareModuleById(sm.getId()), knownValuePrefix + index)); + softwareManagement.createSoftwareModuleMetadata(entityFactory.generateSoftwareModuleMetadata( + softwareManagement.findSoftwareModuleById(sm.getId()), knownKeyPrefix + index, + knownValuePrefix + index)); } final String rsqlSearchValue1 = "value==knownValue1"; @@ -1012,7 +1020,7 @@ public class SoftwareModuleResourceTest extends AbstractIntegrationTestWithMongo char character = 'a'; for (int index = 0; index < amount; index++) { final String str = String.valueOf(character); - final SoftwareModule softwareModule = new SoftwareModule(osType, str, str, str, str); + final SoftwareModule softwareModule = entityFactory.generateSoftwareModule(osType, str, str, str, str); softwareManagement.createSoftwareModule(softwareModule); character++; diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResourceTest.java similarity index 74% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeResourceTest.java rename to hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResourceTest.java index a85e25bed..36d975138 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResourceTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.fest.assertions.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.equalTo; @@ -23,11 +23,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.util.ArrayList; import java.util.List; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.WithUser; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.test.util.WithUser; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; +import org.eclipse.hawkbit.rest.util.JsonBuilder; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.json.JSONException; import org.json.JSONObject; import org.junit.Test; @@ -41,19 +43,19 @@ import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; /** - * Test for {@link SoftwareModuleTypeResource}. + * Test for {@link MgmtSoftwareModuleTypeResource}. * */ @Features("Component Tests - Management API") @Stories("Software Module Type Resource") -public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { +public class MgmtSoftwareModuleTypeResourceTest extends AbstractRestIntegrationTest { @Test @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests.") public void getSoftwareModuleTypes() throws Exception { - SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test123", "TestName123", "Desc123", 5)); + SoftwareModuleType testType = softwareManagement.createSoftwareModuleType( + entityFactory.generateSoftwareModuleType("test123", "TestName123", "Desc123", 5)); testType.setDescription("Desc1234"); testType = softwareManagement.updateSoftwareModuleType(testType); @@ -75,7 +77,8 @@ public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { jsonPath("$content.[?(@.key==" + appType.getKey() + ")][0].name", equalTo(appType.getName()))) .andExpect(jsonPath("$content.[?(@.key==" + appType.getKey() + ")][0].description", equalTo(appType.getDescription()))) - .andExpect(jsonPath("$content.[?(@.key==" + appType.getKey() + ")][0].maxAssignments", equalTo(1))) + .andExpect(jsonPath("$content.[?(@.key==" + appType.getKey() + ")][0].maxAssignments", + equalTo(Integer.MAX_VALUE))) .andExpect(jsonPath("$content.[?(@.key==" + appType.getKey() + ")][0].key", equalTo("application"))) .andExpect(jsonPath("$content.[?(@.key==test123)][0].id", equalTo(testType.getId().intValue()))) .andExpect(jsonPath("$content.[?(@.key==test123)][0].name", equalTo("TestName123"))) @@ -94,40 +97,40 @@ public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests with sorting by MAXASSIGNMENTS field.") public void getSoftwareModuleTypesSortedByMaxAssignments() throws Exception { - SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test123", "TestName123", "Desc123", 5)); + SoftwareModuleType testType = softwareManagement.createSoftwareModuleType( + entityFactory.generateSoftwareModuleType("test123", "TestName123", "Desc123", 5)); testType.setDescription("Desc1234"); testType = softwareManagement.updateSoftwareModuleType(testType); // descending mvc.perform(get("/rest/v1/softwaremoduletypes").accept(MediaType.APPLICATION_JSON) - .param(RestConstants.REQUEST_PARAMETER_SORTING, "MAXASSIGNMENTS:DESC")) + .param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "MAXASSIGNMENTS:DESC")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$content.[0].id", equalTo(testType.getId().intValue()))) - .andExpect(jsonPath("$content.[0].name", equalTo("TestName123"))) - .andExpect(jsonPath("$content.[0].description", equalTo("Desc1234"))) - .andExpect(jsonPath("$content.[0].createdBy", equalTo("uploadTester"))) - .andExpect(jsonPath("$content.[0].createdAt", equalTo(testType.getCreatedAt()))) - .andExpect(jsonPath("$content.[0].lastModifiedBy", equalTo("uploadTester"))) - .andExpect(jsonPath("$content.[0].lastModifiedAt", equalTo(testType.getLastModifiedAt()))) - .andExpect(jsonPath("$content.[0].maxAssignments", equalTo(5))) - .andExpect(jsonPath("$content.[0].key", equalTo("test123"))).andExpect(jsonPath("$total", equalTo(4))); + .andExpect(jsonPath("$content.[1].id", equalTo(testType.getId().intValue()))) + .andExpect(jsonPath("$content.[1].name", equalTo("TestName123"))) + .andExpect(jsonPath("$content.[1].description", equalTo("Desc1234"))) + .andExpect(jsonPath("$content.[1].createdBy", equalTo("uploadTester"))) + .andExpect(jsonPath("$content.[1].createdAt", equalTo(testType.getCreatedAt()))) + .andExpect(jsonPath("$content.[1].lastModifiedBy", equalTo("uploadTester"))) + .andExpect(jsonPath("$content.[1].lastModifiedAt", equalTo(testType.getLastModifiedAt()))) + .andExpect(jsonPath("$content.[1].maxAssignments", equalTo(5))) + .andExpect(jsonPath("$content.[1].key", equalTo("test123"))).andExpect(jsonPath("$total", equalTo(4))); // ascending mvc.perform(get("/rest/v1/softwaremoduletypes").accept(MediaType.APPLICATION_JSON) - .param(RestConstants.REQUEST_PARAMETER_SORTING, "MAXASSIGNMENTS:ASC")) + .param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "MAXASSIGNMENTS:ASC")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$content.[3].id", equalTo(testType.getId().intValue()))) - .andExpect(jsonPath("$content.[3].name", equalTo("TestName123"))) - .andExpect(jsonPath("$content.[3].description", equalTo("Desc1234"))) - .andExpect(jsonPath("$content.[3].createdBy", equalTo("uploadTester"))) - .andExpect(jsonPath("$content.[3].createdAt", equalTo(testType.getCreatedAt()))) - .andExpect(jsonPath("$content.[3].lastModifiedBy", equalTo("uploadTester"))) - .andExpect(jsonPath("$content.[3].lastModifiedAt", equalTo(testType.getLastModifiedAt()))) - .andExpect(jsonPath("$content.[3].maxAssignments", equalTo(5))) - .andExpect(jsonPath("$content.[3].key", equalTo("test123"))).andExpect(jsonPath("$total", equalTo(4))); + .andExpect(jsonPath("$content.[2].id", equalTo(testType.getId().intValue()))) + .andExpect(jsonPath("$content.[2].name", equalTo("TestName123"))) + .andExpect(jsonPath("$content.[2].description", equalTo("Desc1234"))) + .andExpect(jsonPath("$content.[2].createdBy", equalTo("uploadTester"))) + .andExpect(jsonPath("$content.[2].createdAt", equalTo(testType.getCreatedAt()))) + .andExpect(jsonPath("$content.[2].lastModifiedBy", equalTo("uploadTester"))) + .andExpect(jsonPath("$content.[2].lastModifiedAt", equalTo(testType.getLastModifiedAt()))) + .andExpect(jsonPath("$content.[2].maxAssignments", equalTo(5))) + .andExpect(jsonPath("$content.[2].key", equalTo("test123"))).andExpect(jsonPath("$total", equalTo(4))); } @Test @@ -136,9 +139,9 @@ public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { public void createSoftwareModuleTypes() throws JSONException, Exception { final List types = new ArrayList<>(); - types.add(new SoftwareModuleType("test1", "TestName1", "Desc1", 1)); - types.add(new SoftwareModuleType("test2", "TestName2", "Desc2", 2)); - types.add(new SoftwareModuleType("test3", "TestName3", "Desc3", 3)); + types.add(entityFactory.generateSoftwareModuleType("test1", "TestName1", "Desc1", 1)); + types.add(entityFactory.generateSoftwareModuleType("test2", "TestName2", "Desc2", 2)); + types.add(entityFactory.generateSoftwareModuleType("test3", "TestName3", "Desc3", 3)); final MvcResult mvcResult = mvc .perform(post("/rest/v1/softwaremoduletypes/").content(JsonBuilder.softwareModuleTypes(types)) @@ -180,8 +183,8 @@ public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} GET requests.") public void getSoftwareModuleType() throws Exception { - SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test123", "TestName123", "Desc123", 5)); + SoftwareModuleType testType = softwareManagement.createSoftwareModuleType( + entityFactory.generateSoftwareModuleType("test123", "TestName123", "Desc123", 5)); testType.setDescription("Desc1234"); testType = softwareManagement.updateSoftwareModuleType(testType); @@ -201,8 +204,8 @@ public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} DELETE requests (hard delete scenario).") public void deleteSoftwareModuleTypeUnused() throws Exception { - final SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test123", "TestName123", "Desc123", 5)); + final SoftwareModuleType testType = softwareManagement.createSoftwareModuleType( + entityFactory.generateSoftwareModuleType("test123", "TestName123", "Desc123", 5)); assertThat(softwareManagement.countSoftwareModuleTypesAll()).isEqualTo(4); @@ -216,26 +219,24 @@ public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { @WithUser(principal = "uploadTester", allSpPermissions = true) @Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} DELETE requests (soft delete scenario).") public void deleteSoftwareModuleTypeUsed() throws Exception { - final SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test123", "TestName123", "Desc123", 5)); - softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "name", "version", "description", "vendor")); + final SoftwareModuleType testType = softwareManagement.createSoftwareModuleType( + entityFactory.generateSoftwareModuleType("test123", "TestName123", "Desc123", 5)); + softwareManagement.createSoftwareModule( + entityFactory.generateSoftwareModule(testType, "name", "version", "description", "vendor")); assertThat(softwareManagement.countSoftwareModuleTypesAll()).isEqualTo(4); - assertThat(softwareModuleTypeRepository.count()).isEqualTo(4); mvc.perform(delete("/rest/v1/softwaremoduletypes/{smId}", testType.getId())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); - assertThat(softwareModuleTypeRepository.count()).isEqualTo(4); assertThat(softwareManagement.countSoftwareModuleTypesAll()).isEqualTo(3); } @Test @Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} PUT requests.") public void updateSoftwareModuleTypeOnlyDescriptionAndNameUntouched() throws Exception { - final SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test123", "TestName123", "Desc123", 5)); + final SoftwareModuleType testType = softwareManagement.createSoftwareModuleType( + entityFactory.generateSoftwareModuleType("test123", "TestName123", "Desc123", 5)); final String body = new JSONObject().put("id", testType.getId()).put("description", "foobardesc") .put("name", "nameShouldNotBeChanged").toString(); @@ -252,11 +253,11 @@ public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { @Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests with paging.") public void getSoftwareModuleTypesWithoutAddtionalRequestParameters() throws Exception { final int types = 3; - mvc.perform(get(RestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print()) + mvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(types))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(types))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(types))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(types))); } @Test @@ -264,12 +265,12 @@ public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { public void getSoftwareModuleTypesWithPagingLimitRequestParameter() throws Exception { final int types = 3; final int limitSize = 1; - mvc.perform(get(RestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))) + mvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize))); } @Test @@ -278,20 +279,20 @@ public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { final int types = 3; final int offsetParam = 2; final int expectedSize = types - offsetParam; - mvc.perform(get(RestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING) - .param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam)) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(types))) + mvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam)) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(types))) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize))) - .andExpect(jsonPath(TargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize))); + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize))) + .andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize))); } @Test @Description("Ensures that the server is behaving as expected on invalid requests (wrong media type, wrong ID etc.).") public void invalidRequestsOnSoftwaremoduleTypesResource() throws Exception { - final SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test123", "TestName123", "Desc123", 5)); + final SoftwareModuleType testType = softwareManagement.createSoftwareModuleType( + entityFactory.generateSoftwareModuleType("test123", "TestName123", "Desc123", 5)); final List types = new ArrayList<>(); types.add(testType); @@ -329,10 +330,10 @@ public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { @Test @Description("Search erquest of software module types.") public void searchSoftwareModuleTypeRsql() throws Exception { - final SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test123", "TestName123", "Desc123", 5)); - final SoftwareModuleType testType2 = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test1234", "TestName1234", "Desc123", 5)); + final SoftwareModuleType testType = softwareManagement.createSoftwareModuleType( + entityFactory.generateSoftwareModuleType("test123", "TestName123", "Desc123", 5)); + final SoftwareModuleType testType2 = softwareManagement.createSoftwareModuleType( + entityFactory.generateSoftwareModuleType("test1234", "TestName1234", "Desc123", 5)); final String rsqlFindLikeDs1OrDs2 = "name==TestName123,name==TestName1234"; @@ -347,7 +348,7 @@ public class SoftwareModuleTypeResourceTest extends AbstractIntegrationTest { char character = 'a'; for (int index = 0; index < amount; index++) { final String str = String.valueOf(character); - final SoftwareModule softwareModule = new SoftwareModule(osType, str, str, str, str); + final SoftwareModule softwareModule = entityFactory.generateSoftwareModule(osType, str, str, str, str); softwareManagement.createSoftwareModule(softwareModule); character++; diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/TargetResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java similarity index 75% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/TargetResourceTest.java rename to hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java index 8d27d5114..f647106af 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/TargetResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java @@ -6,14 +6,16 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; +import static com.google.common.collect.Lists.newArrayList; import static org.fest.assertions.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -29,15 +31,13 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.WithUser; import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.ActionFields; -import org.eclipse.hawkbit.repository.ActionStatusFields; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.Status; @@ -45,15 +45,18 @@ import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.hawkbit.rest.resource.model.ExceptionInfo; +import org.eclipse.hawkbit.repository.test.util.WithUser; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; +import org.eclipse.hawkbit.rest.exception.MessageNotReadableException; +import org.eclipse.hawkbit.rest.json.model.ExceptionInfo; +import org.eclipse.hawkbit.rest.util.JsonBuilder; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.eclipse.hawkbit.util.IpUtil; import org.json.JSONException; import org.json.JSONObject; import org.junit.Ignore; import org.junit.Test; import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort.Direction; import org.springframework.http.HttpStatus; @@ -68,12 +71,12 @@ import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; /** - * Spring MVC Tests against the TargetResource. + * Spring MVC Tests against the MgmtTargetResource. * */ @Features("Component Tests - Management API") @Stories("Target Resource") -public class TargetResourceTest extends AbstractIntegrationTest { +public class MgmtTargetResourceTest extends AbstractRestIntegrationTest { private static final String TARGET_DESCRIPTION_TEST = "created in test"; @@ -88,6 +91,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { private static final String JSON_PATH_FIELD_CONTENT = ".content"; private static final String JSON_PATH_FIELD_SIZE = ".size"; private static final String JSON_PATH_FIELD_TOTAL = ".total"; + private static final String JSON_PATH_FIELD_LAST_REQUEST_AT = ".lastControllerRequestAt"; // target // $.field @@ -99,6 +103,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { private static final String JSON_PATH_ID = JSON_PATH_ROOT + JSON_PATH_FIELD_ID; private static final String JSON_PATH_CONTROLLERID = JSON_PATH_ROOT + JSON_PATH_FIELD_CONTROLLERID; private static final String JSON_PATH_DESCRIPTION = JSON_PATH_ROOT + JSON_PATH_FIELD_DESCRIPTION; + private static final String JSON_PATH_LAST_REQUEST_AT = JSON_PATH_ROOT + JSON_PATH_FIELD_LAST_REQUEST_AT; @Test @Description("Ensures that actions list is in exptected order.") @@ -107,9 +112,8 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String knownTargetId = "targetId"; final List actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId); actions.get(0).setStatus(Status.FINISHED); - controllerManagament.addUpdateActionStatus( - new ActionStatus(actions.get(0), Status.FINISHED, System.currentTimeMillis(), "testmessage"), - actions.get(0)); + controllerManagament.addUpdateActionStatus(entityFactory.generateActionStatus(actions.get(0), Status.FINISHED, + System.currentTimeMillis(), "testmessage")); final PageRequest pageRequest = new PageRequest(0, 1000, Direction.ASC, ActionFields.ID.getFieldName()); final ActionStatus status = deploymentManagement @@ -117,10 +121,10 @@ public class TargetResourceTest extends AbstractIntegrationTest { .get(0).getActionStatus().stream().sorted((e1, e2) -> Long.compare(e2.getId(), e1.getId())) .collect(Collectors.toList()).get(0); - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + actions.get(0).getId() + "/status") - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)) - .param(RestConstants.REQUEST_PARAMETER_SORTING, "ID:DESC")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actions.get(0).getId() + "/status") + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)) + .param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:DESC")) .andExpect(status().isOk()).andDo(MockMvcResultPrinter.print()) .andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(3))) .andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize))) @@ -138,8 +142,8 @@ public class TargetResourceTest extends AbstractIntegrationTest { public void securityTokenIsNotInResponseIfMissingPermission() throws Exception { final String knownControllerId = "knownControllerId"; - targetManagement.createTarget(new Target(knownControllerId)); - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}", knownControllerId)) + targetManagement.createTarget(entityFactory.generateTarget(knownControllerId)); + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}", knownControllerId)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("securityToken").doesNotExist()); } @@ -151,8 +155,8 @@ public class TargetResourceTest extends AbstractIntegrationTest { public void securityTokenIsInResponseWithCorrectPermission() throws Exception { final String knownControllerId = "knownControllerId"; - final Target createTarget = targetManagement.createTarget(new Target(knownControllerId)); - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}", knownControllerId)) + final Target createTarget = targetManagement.createTarget(entityFactory.generateTarget(knownControllerId)); + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}", knownControllerId)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("securityToken", equalTo(createTarget.getSecurityToken()))); } @@ -168,7 +172,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { createTarget(knownControllerId2); // test - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print()) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(2))) .andExpect(jsonPath("size", equalTo(2))) .andExpect(jsonPath("$content.[?(@.controllerId==" + knownControllerId1 + ")][0].ipAddress", @@ -182,8 +186,8 @@ public class TargetResourceTest extends AbstractIntegrationTest { } private void createTarget(final String controllerId) { - final Target target = new Target(controllerId); - final TargetInfo targetInfo = new TargetInfo(target); + final JpaTarget target = (JpaTarget) entityFactory.generateTarget(controllerId); + final JpaTargetInfo targetInfo = new JpaTargetInfo(target); targetInfo.setAddress(IpUtil.createHttpUri("127.0.0.1").toString()); target.setTargetInfo(targetInfo); targetManagement.createTarget(target); @@ -194,9 +198,8 @@ public class TargetResourceTest extends AbstractIntegrationTest { public void searchActionsRsql() throws Exception { // prepare test - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); - final Target createTarget = targetManagement.createTarget(new Target("knownTargetId")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); + final Target createTarget = targetManagement.createTarget(entityFactory.generateTarget("knownTargetId")); deploymentManagement.assignDistributionSet(dsA, Lists.newArrayList(createTarget)); @@ -204,22 +207,22 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String rsqlFinishedStatus = "status==finished"; final String rsqlPendingOrFinishedStatus = rsqlFinishedStatus + "," + rsqlPendingStatus; // pending status one result - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions?q=" + rsqlPendingStatus, + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions?q=" + rsqlPendingStatus, createTarget.getControllerId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("total", equalTo(1))).andExpect(jsonPath("size", equalTo(1))) .andExpect(jsonPath("content[0].status", equalTo("pending"))); // finished status none result - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions?q=" + rsqlFinishedStatus, + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions?q=" + rsqlFinishedStatus, createTarget.getControllerId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("total", equalTo(0))).andExpect(jsonPath("size", equalTo(0))); // pending or finished status one result - mvc.perform( - get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions?q=" + rsqlPendingOrFinishedStatus, - createTarget.getControllerId())) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1))) - .andExpect(jsonPath("size", equalTo(1))).andExpect(jsonPath("content[0].status", equalTo("pending"))); + mvc.perform(get( + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions?q=" + rsqlPendingOrFinishedStatus, + createTarget.getControllerId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(jsonPath("total", equalTo(1))).andExpect(jsonPath("size", equalTo(1))) + .andExpect(jsonPath("content[0].status", equalTo("pending"))); } @Test @@ -229,7 +232,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { final Target tA = createTargetAndStartAction(); // test - cancel the active action - mvc.perform(delete(RestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions/{actionId}", + mvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions/{actionId}", tA.getControllerId(), tA.getActions().get(0).getId())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isNoContent()); @@ -261,7 +264,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { assertThat(cancelActions).hasSize(1); // test - cancel an cancel action returns forbidden - mvc.perform(delete(RestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions/{actionId}", + mvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions/{actionId}", tA.getControllerId(), cancelActions.get(0).getId())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); } @@ -282,7 +285,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { assertThat(cancelActions.get(0).isCancelingOrCanceled()).isTrue(); // test - force quit an canceled action should return 204 - mvc.perform(delete(RestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions/{actionId}?force=true", + mvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions/{actionId}?force=true", tA.getControllerId(), cancelActions.get(0).getId())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isNoContent()); } @@ -294,7 +297,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { final Target tA = createTargetAndStartAction(); // test - cancel an cancel action returns forbidden - mvc.perform(delete(RestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions/{actionId}?force=true", + mvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/actions/{actionId}?force=true", tA.getControllerId(), tA.getActions().get(0).getId())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); } @@ -303,9 +306,9 @@ public class TargetResourceTest extends AbstractIntegrationTest { @Description("Ensures that deletion is executed if permitted.") public void deleteTargetReturnsOK() throws Exception { final String knownControllerId = "knownControllerIdDelete"; - targetManagement.createTarget(new Target(knownControllerId)); + targetManagement.createTarget(entityFactory.generateTarget(knownControllerId)); - mvc.perform(delete(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId)) + mvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId)) .andExpect(status().isOk()); final Target findTargetByControllerID = targetManagement.findTargetByControllerID(knownControllerId); @@ -317,7 +320,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { public void deleteTargetWhichDoesNotExistsLeadsToEntityNotFound() throws Exception { final String knownControllerId = "knownControllerIdDelete"; - mvc.perform(delete(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId)) + mvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId)) .andExpect(status().isNotFound()); } @@ -325,7 +328,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { @Description("Ensures that update is refused with not found if target does not exist.") public void updateTargetWhichDoesNotExistsLeadsToEntityNotFound() throws Exception { final String knownControllerId = "knownControllerIdUpdate"; - mvc.perform(put(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId).content("{}") + mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId).content("{}") .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); } @@ -339,12 +342,12 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String body = new JSONObject().put("description", knownNewDescription).toString(); // prepare - final Target t = new Target(knownControllerId); + final Target t = entityFactory.generateTarget(knownControllerId); t.setDescription("old description"); t.setName(knownNameNotModiy); targetManagement.createTarget(t); - mvc.perform(put(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId).content(body) + mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId).content(body) .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("$.controllerId", equalTo(knownControllerId))) .andExpect(jsonPath("$.description", equalTo(knownNewDescription))) @@ -355,6 +358,54 @@ public class TargetResourceTest extends AbstractIntegrationTest { assertThat(findTargetByControllerID.getName()).isEqualTo(knownNameNotModiy); } + @Test + @Description("Ensures that target update request is reflected by repository.") + public void updateTargetSecurityToken() throws Exception { + final String knownControllerId = "123"; + final String knownNewToken = "6567576565"; + final String knownNameNotModiy = "nameNotModiy"; + final String body = new JSONObject().put("securityToken", knownNewToken).toString(); + + // prepare + final Target t = entityFactory.generateTarget(knownControllerId); + t.setName(knownNameNotModiy); + targetManagement.createTarget(t); + + mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId).content(body) + .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(jsonPath("$.controllerId", equalTo(knownControllerId))) + .andExpect(jsonPath("$.securityToken", equalTo(knownNewToken))) + .andExpect(jsonPath("$.name", equalTo(knownNameNotModiy))); + + final Target findTargetByControllerID = targetManagement.findTargetByControllerID(knownControllerId); + assertThat(findTargetByControllerID.getSecurityToken()).isEqualTo(knownNewToken); + assertThat(findTargetByControllerID.getName()).isEqualTo(knownNameNotModiy); + } + + @Test + @Description("Ensures that target update request is reflected by repository.") + public void updateTargetAddress() throws Exception { + final String knownControllerId = "123"; + final String knownNewAddress = "amqp://test123/foobar"; + final String knownNameNotModiy = "nameNotModiy"; + final String body = new JSONObject().put("address", knownNewAddress).toString(); + + // prepare + final Target t = entityFactory.generateTarget(knownControllerId); + t.setName(knownNameNotModiy); + targetManagement.createTarget(t); + + mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId).content(body) + .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(jsonPath("$.controllerId", equalTo(knownControllerId))) + .andExpect(jsonPath("$.address", equalTo(knownNewAddress))) + .andExpect(jsonPath("$.name", equalTo(knownNameNotModiy))); + + final Target findTargetByControllerID = targetManagement.findTargetByControllerID(knownControllerId); + assertThat(findTargetByControllerID.getTargetInfo().getAddress().toString()).isEqualTo(knownNewAddress); + assertThat(findTargetByControllerID.getName()).isEqualTo(knownNameNotModiy); + } + @Test @Description("Ensures that target query returns list of targets in defined format.") public void getTargetWithoutAddtionalRequestParameters() throws Exception { @@ -364,7 +415,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String idC = "c"; final String linksHrefPrefix = "http://localhost/rest/v1/targets/"; createTargetsAlphabetical(knownTargetAmount); - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING)).andExpect(status().isOk()) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)).andExpect(status().isOk()) .andDo(MockMvcResultPrinter.print()) .andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(knownTargetAmount))) .andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(knownTargetAmount))) @@ -377,6 +428,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { .andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].controllerId", equalTo(idA))) .andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].createdBy", equalTo("bumlux"))) .andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].updateStatus", equalTo("unknown"))) + .andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].lastControllerRequestAt", notNullValue())) // idB .andExpect(jsonPath("$content.[?(@.name==" + idB + ")][0]._links.self.href", equalTo(linksHrefPrefix + idB))) @@ -385,6 +437,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { .andExpect(jsonPath("$content.[?(@.name==" + idB + ")][0].controllerId", equalTo(idB))) .andExpect(jsonPath("$content.[?(@.name==" + idB + ")][0].createdBy", equalTo("bumlux"))) .andExpect(jsonPath("$content.[?(@.name==" + idB + ")][0].updateStatus", equalTo("unknown"))) + .andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].lastControllerRequestAt", notNullValue())) // idC .andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0]._links.self.href", equalTo(linksHrefPrefix + idC))) @@ -392,7 +445,8 @@ public class TargetResourceTest extends AbstractIntegrationTest { .andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0].description", equalTo(idC))) .andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0].controllerId", equalTo(idC))) .andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0].createdBy", equalTo("bumlux"))) - .andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0].updateStatus", equalTo("unknown"))); + .andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0].updateStatus", equalTo("unknown"))) + .andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].lastControllerRequestAt", notNullValue())); } @Test @@ -404,8 +458,9 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String idA = "a"; final String linksHrefPrefix = "http://localhost/rest/v1/targets/"; - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING).param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, - String.valueOf(limitSize))).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print()) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))) + .andExpect(status().isOk()).andDo(MockMvcResultPrinter.print()) .andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(knownTargetAmount))) .andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize))) .andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize))) @@ -431,9 +486,9 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String linksHrefPrefix = "http://localhost/rest/v1/targets/"; createTargetsAlphabetical(knownTargetAmount); - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING) - .param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam)) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(knownTargetAmount))) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam)) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(knownTargetAmount))) .andExpect(status().isOk()).andDo(MockMvcResultPrinter.print()) .andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(knownTargetAmount))) .andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize))) @@ -469,14 +524,15 @@ public class TargetResourceTest extends AbstractIntegrationTest { // create first a target which can be retrieved by rest interface final String knownControllerId = "1"; final String knownName = "someName"; - createSingleTarget(knownControllerId, knownName); + final Target target = createSingleTarget(knownControllerId, knownName); final String hrefPrefix = "http://localhost/rest/v1/targets/" + knownControllerId + "/"; // test - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId)) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath(JSON_PATH_NAME, equalTo(knownName))) .andExpect(jsonPath(JSON_PATH_CONTROLLERID, equalTo(knownControllerId))) .andExpect(jsonPath(JSON_PATH_DESCRIPTION, equalTo(TARGET_DESCRIPTION_TEST))) + .andExpect(jsonPath(JSON_PATH_LAST_REQUEST_AT, equalTo(target.getTargetInfo().getLastTargetQuery()))) .andExpect(jsonPath("$.pollStatus", hasKey("lastRequestAt"))) .andExpect(jsonPath("$.pollStatus", hasKey("nextExpectedRequestAt"))) .andExpect(jsonPath("$.pollStatus.overdue", equalTo(false))) @@ -491,7 +547,8 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String targetIdNotExists = "bubu"; // test - final MvcResult mvcResult = mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetIdNotExists)) + final MvcResult mvcResult = mvc + .perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetIdNotExists)) .andExpect(status().isNotFound()).andReturn(); // verify response json exception message @@ -509,7 +566,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { // test - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId + "/assignedDS")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId + "/assignedDS")) .andExpect(status().isNoContent()).andExpect(content().string("")); } @@ -520,8 +577,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String knownControllerId = "1"; final String knownName = "someName"; createSingleTarget(knownControllerId, knownName); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); deploymentManagement.assignDistributionSet(ds.getId(), knownControllerId); // test @@ -529,7 +585,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { final SoftwareModule os = ds.findFirstModuleByType(osType); final SoftwareModule jvm = ds.findFirstModuleByType(runtimeType); final SoftwareModule bApp = ds.findFirstModuleByType(appType); - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId + "/assignedDS")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId + "/assignedDS")) .andExpect(status().isOk()).andDo(MockMvcResultPrinter.print()) .andExpect(jsonPath(JSON_PATH_ID, equalTo(ds.getId().intValue()))) .andExpect(jsonPath(JSON_PATH_NAME, equalTo(ds.getName()))) @@ -579,7 +635,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { // test - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId + "/installedDS")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId + "/installedDS")) .andExpect(status().isNoContent()).andExpect(content().string("")); } @@ -591,18 +647,18 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String knownControllerId = "1"; final String knownName = "someName"; createSingleTarget(knownControllerId, knownName); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); // assign ds to target - deploymentManagement.assignDistributionSet(ds.getId(), knownControllerId); + final Long actionId = deploymentManagement.assignDistributionSet(ds.getId(), knownControllerId).getActions() + .get(0); // give feedback, so installedDS is in SNYC - feedbackToByInSync(knownControllerId, ds); + feedbackToByInSync(actionId); // test final SoftwareModule os = ds.findFirstModuleByType(osType); final SoftwareModule jvm = ds.findFirstModuleByType(runtimeType); final SoftwareModule bApp = ds.findFirstModuleByType(appType); - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId + "/installedDS")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId + "/installedDS")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath(JSON_PATH_ID, equalTo(ds.getId().intValue()))) .andExpect(jsonPath(JSON_PATH_NAME, equalTo(ds.getName()))) @@ -646,7 +702,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { public void createTargetWithoutPayloadBadRequest() throws Exception { final MvcResult mvcResult = mvc - .perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING).contentType(MediaType.APPLICATION_JSON)) + .perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()).andReturn(); assertThat(targetManagement.countTargetsAll()).isEqualTo(0); @@ -663,7 +719,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String notJson = "abc"; final MvcResult mvcResult = mvc - .perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING).content(notJson) + .perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING).content(notJson) .contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()).andReturn(); @@ -678,13 +734,14 @@ public class TargetResourceTest extends AbstractIntegrationTest { @Test public void createTargetsListReturnsSuccessful() throws Exception { - final Target test1 = new Target("id1"); + final Target test1 = entityFactory.generateTarget("id1", "token"); test1.setDescription("testid1"); test1.setName("testname1"); - final Target test2 = new Target("id2"); + test1.getTargetInfo().setAddress("amqp://test123/foobar"); + final Target test2 = entityFactory.generateTarget("id2"); test2.setDescription("testid2"); test2.setName("testname2"); - final Target test3 = new Target("id3"); + final Target test3 = entityFactory.generateTarget("id3"); test3.setName("testname3"); test3.setDescription("testid3"); @@ -694,7 +751,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { targets.add(test3); final MvcResult mvcResult = mvc - .perform(post("/rest/v1/targets/").content(JsonBuilder.targets(targets)) + .perform(post("/rest/v1/targets/").content(JsonBuilder.targets(targets, true)) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) @@ -703,6 +760,8 @@ public class TargetResourceTest extends AbstractIntegrationTest { .andExpect(jsonPath("[0].description", equalTo("testid1"))) .andExpect(jsonPath("[0].createdAt", not(equalTo(0)))) .andExpect(jsonPath("[0].createdBy", equalTo("bumlux"))) + .andExpect(jsonPath("[0].securityToken", equalTo("token"))) + .andExpect(jsonPath("[0].address", equalTo("amqp://test123/foobar"))) .andExpect(jsonPath("[1].name", equalTo("testname2"))) .andExpect(jsonPath("[1].createdBy", equalTo("bumlux"))) .andExpect(jsonPath("[1].controllerId", equalTo("id2"))) @@ -728,6 +787,9 @@ public class TargetResourceTest extends AbstractIntegrationTest { assertThat(targetManagement.findTargetByControllerID("id1")).isNotNull(); assertThat(targetManagement.findTargetByControllerID("id1").getName()).isEqualTo("testname1"); assertThat(targetManagement.findTargetByControllerID("id1").getDescription()).isEqualTo("testid1"); + assertThat(targetManagement.findTargetByControllerID("id1").getSecurityToken()).isEqualTo("token"); + assertThat(targetManagement.findTargetByControllerID("id1").getTargetInfo().getAddress().toString()) + .isEqualTo("amqp://test123/foobar"); assertThat(targetManagement.findTargetByControllerID("id2")).isNotNull(); assertThat(targetManagement.findTargetByControllerID("id2").getName()).isEqualTo("testname2"); assertThat(targetManagement.findTargetByControllerID("id2").getDescription()).isEqualTo("testid2"); @@ -743,7 +805,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String knownDescription = "someDescription"; final String createTargetsJson = getCreateTargetsListJsonString(knownControllerId, knownName, knownDescription); - mvc.perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING).content(createTargetsJson) + mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING).content(createTargetsJson) .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .andExpect(status().is2xxSuccessful()); @@ -764,12 +826,12 @@ public class TargetResourceTest extends AbstractIntegrationTest { // create a taret first to provoke a already exists error - mvc.perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING).content(createTargetsJson) + mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING).content(createTargetsJson) .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .andExpect(status().is2xxSuccessful()); // create another one to retrieve the entity already exists exception final MvcResult mvcResult = mvc - .perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING).content(createTargetsJson) + .perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING).content(createTargetsJson) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().is(HttpStatus.CONFLICT.value())).andReturn(); @@ -792,7 +854,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String createTargetsJson = getCreateTargetsListJsonStringWithAdditionalNotExistingAttribute( knownControllerId, knownName, knownDescription); - mvc.perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING).content(createTargetsJson) + mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING).content(createTargetsJson) .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .andExpect(status().is2xxSuccessful()); @@ -807,13 +869,13 @@ public class TargetResourceTest extends AbstractIntegrationTest { @Test public void getActionWithEmptyResult() throws Exception { final String knownTargetId = "targetId"; - final Target target = new Target(knownTargetId); + final Target target = entityFactory.generateTarget(knownTargetId); targetManagement.createTarget(target); - mvc.perform(get( - RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + RestConstants.TARGET_V1_ACTIONS)) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("size", equalTo(0))) - .andExpect(jsonPath("content", hasSize(0))).andExpect(jsonPath("total", equalTo(0))); + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(jsonPath("size", equalTo(0))).andExpect(jsonPath("content", hasSize(0))) + .andExpect(jsonPath("total", equalTo(0))); } @Test @@ -821,9 +883,10 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String knownTargetId = "targetId"; final List actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId); - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + actions.get(0).getId())).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isOk()).andExpect(jsonPath("id", equalTo(actions.get(0).getId().intValue()))) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actions.get(0).getId())) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(jsonPath("id", equalTo(actions.get(0).getId().intValue()))) .andExpect(jsonPath("type", equalTo("cancel"))).andExpect(jsonPath("status", equalTo("pending"))) .andExpect(jsonPath("_links.self.href", equalTo(generateActionSelfLink(knownTargetId, actions.get(0))))) .andExpect(jsonPath("_links.canceledaction.href", @@ -837,9 +900,8 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String knownTargetId = "targetId"; final List actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId); - mvc.perform(get( - RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + RestConstants.TARGET_V1_ACTIONS) - .param(RestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS).param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("content.[1].id", equalTo(actions.get(1).getId().intValue()))) .andExpect(jsonPath("content.[1].type", equalTo("update"))) @@ -866,9 +928,10 @@ public class TargetResourceTest extends AbstractIntegrationTest { .sorted((e1, e2) -> Long.compare(e2.getId(), e1.getId())).collect(Collectors.toList()); // sort is default descending order, latest status first - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + RestConstants.TARGET_V1_ACTION_STATUS)) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + + MgmtRestConstants.TARGET_V1_ACTION_STATUS)).andDo(MockMvcResultPrinter.print()) + .andExpect(status().isOk()) .andExpect(jsonPath("content.[0].id", equalTo(actionStatus.get(0).getId().intValue()))) .andExpect(jsonPath("content.[0].type", equalTo("canceling"))) .andExpect(jsonPath("content.[0].messages", hasItem("manual cancelation requested"))) @@ -890,9 +953,10 @@ public class TargetResourceTest extends AbstractIntegrationTest { .sorted((e1, e2) -> Long.compare(e1.getId(), e2.getId())).collect(Collectors.toList()); // descending order - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + RestConstants.TARGET_V1_ACTION_STATUS) - .param(RestConstants.REQUEST_PARAMETER_SORTING, "REPORTEDAT:DESC")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + + MgmtRestConstants.TARGET_V1_ACTION_STATUS).param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, + "REPORTEDAT:DESC")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("content.[0].id", equalTo(actionStatus.get(1).getId().intValue()))) .andExpect(jsonPath("content.[0].type", equalTo("canceling"))) @@ -906,9 +970,10 @@ public class TargetResourceTest extends AbstractIntegrationTest { .andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2))); // ascending order - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + RestConstants.TARGET_V1_ACTION_STATUS) - .param(RestConstants.REQUEST_PARAMETER_SORTING, "REPORTEDAT:ASC")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + + MgmtRestConstants.TARGET_V1_ACTION_STATUS).param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, + "REPORTEDAT:ASC")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("content.[1].id", equalTo(actionStatus.get(1).getId().intValue()))) .andExpect(jsonPath("content.[1].type", equalTo("canceling"))) @@ -932,9 +997,10 @@ public class TargetResourceTest extends AbstractIntegrationTest { .sorted((e1, e2) -> Long.compare(e1.getId(), e2.getId())).collect(Collectors.toList()); // Page 1 - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + RestConstants.TARGET_V1_ACTION_STATUS) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1))) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + + MgmtRestConstants.TARGET_V1_ACTION_STATUS).param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, + String.valueOf(1))) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("content.[0].id", equalTo(actionStatus.get(1).getId().intValue()))) .andExpect(jsonPath("content.[0].type", equalTo("canceling"))) @@ -945,10 +1011,11 @@ public class TargetResourceTest extends AbstractIntegrationTest { .andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(1))); // Page 2 - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + RestConstants.TARGET_V1_ACTION_STATUS) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1)) - .param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1))) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + + MgmtRestConstants.TARGET_V1_ACTION_STATUS) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1)) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1))) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("content.[0].id", equalTo(actionStatus.get(0).getId().intValue()))) .andExpect(jsonPath("content.[0].type", equalTo("running"))) @@ -964,10 +1031,10 @@ public class TargetResourceTest extends AbstractIntegrationTest { final List actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId); // page 1: one entry - mvc.perform(get( - RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + RestConstants.TARGET_V1_ACTIONS) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1)) - .param(RestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1)) + .param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("content.[0].id", equalTo(actions.get(0).getId().intValue()))) .andExpect(jsonPath("content.[0].type", equalTo("cancel"))) @@ -979,12 +1046,12 @@ public class TargetResourceTest extends AbstractIntegrationTest { .andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(1))); // page 2: one entry - mvc.perform(get( - RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + RestConstants.TARGET_V1_ACTIONS) - .param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1)) - .param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1)) - .param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1)) - .param(RestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1)) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1)) + .param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1)) + .param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(jsonPath("content.[0].id", equalTo(actions.get(1).getId().intValue()))) .andExpect(jsonPath("content.[0].type", equalTo("update"))) @@ -997,33 +1064,30 @@ public class TargetResourceTest extends AbstractIntegrationTest { } private String generateActionSelfLink(final String knownTargetId, final Action action) { - return "http://localhost" + RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + action.getId(); + return "http://localhost" + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + action.getId(); } private String generateCanceledactionreferenceLink(final String knownTargetId, final Action action) { - return "http://localhost" + RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + action.getId(); + return "http://localhost" + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + action.getId(); } private String generateStatusreferenceLink(final String knownTargetId, final Action action) { - return "http://localhost" + RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + RestConstants.TARGET_V1_ACTION_STATUS - + "?offset=0&limit=50&sort=id:DESC"; + return "http://localhost" + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + + MgmtRestConstants.TARGET_V1_ACTION_STATUS + "?offset=0&limit=50&sort=id:DESC"; } private List generateTargetWithTwoUpdatesWithOneOverride(final String knownTargetId) throws InterruptedException { - final PageRequest pageRequest = new PageRequest(0, 100, Direction.ASC, ActionStatusFields.ID.getFieldName()); - - Target target = new Target(knownTargetId); + Target target = entityFactory.generateTarget(knownTargetId); target = targetManagement.createTarget(target); final List targets = new ArrayList<>(); targets.add(target); - final Iterator sets = TestDataUtil - .generateDistributionSets(2, softwareManagement, distributionSetManagement).iterator(); + final Iterator sets = testdataFactory.createDistributionSets(2).iterator(); final DistributionSet one = sets.next(); final DistributionSet two = sets.next(); @@ -1035,8 +1099,8 @@ public class TargetResourceTest extends AbstractIntegrationTest { Thread.sleep(10); deploymentManagement.assignDistributionSet(two, updatedTargets); - // two updates, one cancelation - final List actions = actionRepository.findAll(pageRequest).getContent(); + // two updates, one cancellation + final List actions = deploymentManagement.findActionsByTarget(target); assertThat(actions).hasSize(2); return actions; @@ -1047,9 +1111,10 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String knownTargetId = "targetId"; final List actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId); - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + actions.get(1).getId())).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isOk()).andExpect(jsonPath("id", equalTo(actions.get(1).getId().intValue()))) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actions.get(1).getId())) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(jsonPath("id", equalTo(actions.get(1).getId().intValue()))) .andExpect(jsonPath("type", equalTo("update"))).andExpect(jsonPath("status", equalTo("pending"))) .andExpect(jsonPath("_links.self.href", equalTo(generateActionSelfLink(knownTargetId, actions.get(1))))) .andExpect(jsonPath("_links.distributionset.href", @@ -1062,11 +1127,10 @@ public class TargetResourceTest extends AbstractIntegrationTest { @Test public void assignDistributionSetToTarget() throws Exception { - final Target target = targetManagement.createTarget(new Target("fsdfsd")); - final DistributionSet set = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); + targetManagement.createTarget(entityFactory.generateTarget("fsdfsd")); + final DistributionSet set = testdataFactory.createDistributionSet("one"); - mvc.perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS") + mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS") .content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); @@ -1076,15 +1140,14 @@ public class TargetResourceTest extends AbstractIntegrationTest { @Test public void assignDistributionSetToTargetWithActionTimeForcedAndTime() throws Exception { - final Target target = targetManagement.createTarget(new Target("fsdfsd")); - final DistributionSet set = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); + final Target target = targetManagement.createTarget(entityFactory.generateTarget("fsdfsd")); + final DistributionSet set = testdataFactory.createDistributionSet("one"); final long forceTime = System.currentTimeMillis(); final String body = new JSONObject().put("id", set.getId()).put("type", "timeforced") .put("forcetime", forceTime).toString(); - mvc.perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS").content(body) + mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS").content(body) .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); @@ -1098,28 +1161,27 @@ public class TargetResourceTest extends AbstractIntegrationTest { @Test public void invalidRequestsOnAssignDistributionSetToTarget() throws Exception { - final DistributionSet set = TestDataUtil.generateDistributionSet("one", softwareManagement, - distributionSetManagement); + final DistributionSet set = testdataFactory.createDistributionSet("one"); - mvc.perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS") + mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS") .content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound()); - targetManagement.createTarget(new Target("fsdfsd")); + targetManagement.createTarget(entityFactory.generateTarget("fsdfsd")); - mvc.perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS") + mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS") .content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); - mvc.perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS").content("{\"id\":12345678}") - .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isNotFound()); + mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS") + .content("{\"id\":12345678}").contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound()); - mvc.perform(delete(RestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS") + mvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS") .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); - mvc.perform(put(RestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS") + mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS") .content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed()); @@ -1130,28 +1192,28 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String knownTargetId = "targetId"; // target does not exist - mvc.perform(get( - RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + RestConstants.TARGET_V1_ACTIONS)) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound()); + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS)).andDo(MockMvcResultPrinter.print()) + .andExpect(status().isNotFound()); final List actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId); final Long actionId = actions.get(0).getId(); // should work now - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + actionId)).andDo(MockMvcResultPrinter.print()) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); // action does not exist - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/12321")).andDo(MockMvcResultPrinter.print()) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/12321")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); // not allowed methods - mvc.perform(put(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + actionId)).andDo(MockMvcResultPrinter.print()) + mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); - mvc.perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + actionId)).andDo(MockMvcResultPrinter.print()) + mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); } @@ -1160,31 +1222,31 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String knownTargetId = "targetId"; // target does not exist - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/1/status")).andDo(MockMvcResultPrinter.print()) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/1/status")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); final List actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId); final Long actionId = actions.get(0).getId(); // should work now - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + actionId + "/status")).andDo(MockMvcResultPrinter.print()) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId + "/status")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); // action does not exist - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/12321/status")).andDo(MockMvcResultPrinter.print()) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/12321/status")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); // not allowed methods - mvc.perform(delete(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + actionId + "/status")).andDo(MockMvcResultPrinter.print()) + mvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId + "/status")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); - mvc.perform(put(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + actionId + "/status")).andDo(MockMvcResultPrinter.print()) + mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId + "/status")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); - mvc.perform(post(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" - + RestConstants.TARGET_V1_ACTIONS + "/" + actionId + "/status")).andDo(MockMvcResultPrinter.print()) + mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId + "/status")).andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); } @@ -1195,12 +1257,12 @@ public class TargetResourceTest extends AbstractIntegrationTest { final Map knownControllerAttrs = new HashMap<>(); knownControllerAttrs.put("a", "1"); knownControllerAttrs.put("b", "2"); - final Target target = new Target(knownTargetId); + final Target target = entityFactory.generateTarget(knownTargetId); targetManagement.createTarget(target); controllerManagament.updateControllerAttributes(knownTargetId, knownControllerAttrs); // test query target over rest resource - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/attributes")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/attributes")) .andDo(MockMvcResultPrinter.print()).andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.a", equalTo("1"))).andExpect(jsonPath("$.b", equalTo("2"))); } @@ -1209,11 +1271,11 @@ public class TargetResourceTest extends AbstractIntegrationTest { public void getControllerEmptyAttributesReturnsNoContent() throws Exception { // create target with attributes final String knownTargetId = "targetIdWithAttributes"; - final Target target = new Target(knownTargetId); + final Target target = entityFactory.generateTarget(knownTargetId); targetManagement.createTarget(target); // test query target over rest resource - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/attributes")) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/attributes")) .andDo(MockMvcResultPrinter.print()).andExpect(status().is(HttpStatus.NO_CONTENT.value())); } @@ -1224,7 +1286,7 @@ public class TargetResourceTest extends AbstractIntegrationTest { final String rsqlFindAOrB = "controllerId==a,controllerId==b"; - mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "?q=" + rsqlFindAOrB)) + mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "?q=" + rsqlFindAOrB)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("size", equalTo(2))) .andExpect(jsonPath("total", equalTo(2))).andExpect(jsonPath("content[0].controllerId", equalTo("a"))) .andExpect(jsonPath("content[1].controllerId", equalTo("b"))); @@ -1242,65 +1304,57 @@ public class TargetResourceTest extends AbstractIntegrationTest { + "\"}]"; } - private void createSingleTarget(final String controllerId, final String name) { - final Target target = new Target(controllerId); + private Target createSingleTarget(final String controllerId, final String name) { + final Target target = entityFactory.generateTarget(controllerId); target.setName(name); target.setDescription(TARGET_DESCRIPTION_TEST); targetManagement.createTarget(target); - controllerManagament.updateLastTargetQuery(controllerId, null); + return controllerManagament.updateLastTargetQuery(controllerId, null); } /** - * creating targets with the given amount by setting name, id etc from the - * alphabet [a-z] using the ASCII. - * + * Creating targets with the given amount by setting name, id etc from the + * alphabet [a-z] using ASCII. + * * @param amount + * The number of targets to create */ private void createTargetsAlphabetical(final int amount) { char character = 'a'; for (int index = 0; index < amount; index++) { final String str = String.valueOf(character); - final Target target = new Target(str); + final Target target = entityFactory.generateTarget(str); target.setName(str); target.setDescription(str); - final Target savedTarget = targetManagement.createTarget(target); - assertThat(savedTarget.getLastModifiedBy()).isNotNull(); + targetManagement.createTarget(target); + controllerManagament.updateLastTargetQuery(str, null); character++; } } /** - * helper method to give feedback mark an target IN_SNCY - * - * @param controllerId - * the controller id to give feedback to - * @param savedSet - * the distribution set - * @throws Exception - * @throws JSONException + * helper method to give feedback mark an target IN_SYNC + * */ - private void feedbackToByInSync(final String controllerId, final DistributionSet savedSet) - throws Exception, JSONException { - final Pageable pageReq = new PageRequest(0, 100); - final Action action = actionRepository.findByDistributionSet(pageReq, savedSet).getContent().get(0); + private void feedbackToByInSync(final Long actionId) { + final Action action = deploymentManagement.findAction(actionId); - final ActionStatus actionStatus = new ActionStatus(action, Status.FINISHED, 0l); - controllerManagement.addUpdateActionStatus(actionStatus, action); + final ActionStatus actionStatus = entityFactory.generateActionStatus(action, Status.FINISHED, 0L); + controllerManagement.addUpdateActionStatus(actionStatus); } /** * helper method to create a target and start an action on it. - * + * * @return The targetid of the created target. */ private Target createTargetAndStartAction() { // prepare test - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); final Target tA = targetManagement - .createTarget(TestDataUtil.buildTargetFixture("target-id-A", "first description")); + .createTarget(testdataFactory.generateTarget("target-id-A", "first description")); // assign a distribution set so we get an active update action - deploymentManagement.assignDistributionSet(dsA, Lists.newArrayList(tA)); + deploymentManagement.assignDistributionSet(dsA, newArrayList(tA)); // verify active action final Slice actionsByTarget = deploymentManagement.findActionsByTarget(new PageRequest(0, 100), tA); assertThat(actionsByTarget.getContent()).hasSize(1); diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/ResourceUtility.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/ResourceUtility.java similarity index 77% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/ResourceUtility.java rename to hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/ResourceUtility.java index 9e99031e9..e94d1b857 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/ResourceUtility.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/ResourceUtility.java @@ -6,13 +6,13 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import java.io.IOException; -import org.eclipse.hawkbit.rest.resource.model.ExceptionInfo; -import org.eclipse.hawkbit.rest.resource.model.PagedList; -import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactRest; +import org.eclipse.hawkbit.mgmt.json.model.PagedList; +import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact; +import org.eclipse.hawkbit.rest.json.model.ExceptionInfo; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; @@ -33,9 +33,9 @@ public final class ResourceUtility { return mapper.readValue(jsonExceptionResponse, ExceptionInfo.class); } - static ArtifactRest convertArtifactResponse(final String jsonResponse) + static MgmtArtifact convertArtifactResponse(final String jsonResponse) throws JsonParseException, JsonMappingException, IOException { - return mapper.readValue(jsonResponse, ArtifactRest.class); + return mapper.readValue(jsonResponse, MgmtArtifact.class); } diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SMRessourceMisingMongoDbConnectionTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/SMRessourceMisingMongoDbConnectionTest.java similarity index 78% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SMRessourceMisingMongoDbConnectionTest.java rename to hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/SMRessourceMisingMongoDbConnectionTest.java index 664dc861c..de0411006 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SMRessourceMisingMongoDbConnectionTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/SMRessourceMisingMongoDbConnectionTest.java @@ -6,18 +6,18 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.mgmt.rest.resource; import static org.fest.assertions.api.Assertions.assertThat; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.apache.commons.lang3.RandomStringUtils; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.MockMvcResultPrinter; import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.rest.resource.model.ExceptionInfo; +import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; +import org.eclipse.hawkbit.rest.json.model.ExceptionInfo; +import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.mock.web.MockMultipartFile; @@ -28,12 +28,13 @@ import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; /** - * Tests {@link SoftwareModuleResource} in case of missing MongoDB connection. + * Tests {@link MgmtSoftwareModuleResource} in case of missing MongoDB + * connection. * */ @Features("Component Tests - Management API") @Stories("Download Resource") -public class SMRessourceMisingMongoDbConnectionTest extends AbstractIntegrationTest { +public class SMRessourceMisingMongoDbConnectionTest extends AbstractRestIntegrationTest { @BeforeClass public static void initialize() { @@ -47,11 +48,11 @@ public class SMRessourceMisingMongoDbConnectionTest extends AbstractIntegrationT public void missingMongoDbConnectionResultsInErrorAtUpload() throws Exception { assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0); - assertThat(artifactRepository.findAll()).hasSize(0); - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", - "version 1", null, null); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(0); + SoftwareModule sm = entityFactory.generateSoftwareModule( + softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); - assertThat(artifactRepository.findAll()).hasSize(0); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(0); // create test file final byte random[] = RandomStringUtils.random(5 * 1024).getBytes(); @@ -69,7 +70,7 @@ public class SMRessourceMisingMongoDbConnectionTest extends AbstractIntegrationT assertThat(exceptionInfo.getMessage()).isEqualTo(SpServerError.SP_ARTIFACT_UPLOAD_FAILED.getMessage()); // ensure that the JPA transaction was rolled back - assertThat(artifactRepository.findAll()).hasSize(0); + assertThat(artifactManagement.countLocalArtifactsAll()).isEqualTo(0); } diff --git a/hawkbit-rest-resource/src/test/resources/application-test.properties b/hawkbit-mgmt-resource/src/test/resources/application-test.properties similarity index 82% rename from hawkbit-rest-resource/src/test/resources/application-test.properties rename to hawkbit-mgmt-resource/src/test/resources/application-test.properties index 92506caa4..cd98bb23f 100644 --- a/hawkbit-rest-resource/src/test/resources/application-test.properties +++ b/hawkbit-mgmt-resource/src/test/resources/application-test.properties @@ -7,22 +7,8 @@ # http://www.eclipse.org/legal/epl-v10.html # -# used if IM profile is disabled -security.ignored=true - -# IM required for integration tests -spring.profiles.active=im,suiteembedded,artifactrepository,redis - -server.port=12222 - -spring.data.mongodb.uri=mongodb://localhost/spArtifactRepository${random.value} -spring.data.mongodb.port=28017 - - # supported: H2, MYSQL hawkbit.server.database=H2 -hawkbit.server.database.env=TEST -spring.main.show_banner=false hawkbit.server.ddi.security.authentication.header=true diff --git a/hawkbit-mgmt-resource/src/test/resources/logback.xml b/hawkbit-mgmt-resource/src/test/resources/logback.xml new file mode 100644 index 000000000..30060d1c6 --- /dev/null +++ b/hawkbit-mgmt-resource/src/test/resources/logback.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hawkbit-repository/.gitignore b/hawkbit-repository/.gitignore new file mode 100644 index 000000000..6a3b2b405 --- /dev/null +++ b/hawkbit-repository/.gitignore @@ -0,0 +1 @@ +/.springBeans diff --git a/hawkbit-repository/hawkbit-repository-api/README.md b/hawkbit-repository/hawkbit-repository-api/README.md new file mode 100644 index 000000000..8000ad390 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/README.md @@ -0,0 +1,6 @@ +# hawkBit repository API + +API for repository access. Contains: + +- Entity Model +- Management service API \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/pom.xml b/hawkbit-repository/hawkbit-repository-api/pom.xml new file mode 100644 index 000000000..050a9a070 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + org.eclipse.hawkbit + hawkbit-repository + 0.2.0-SNAPSHOT + + hawkbit-repository-api + hawkBit :: Repository API + + + + org.eclipse.hawkbit + hawkbit-security-core + ${project.version} + + + javax.validation + validation-api + + + org.hibernate + hibernate-validator + + + cz.jirutka.rsql + rsql-parser + + + org.springframework.hateoas + spring-hateoas + + + org.springframework.boot + spring-boot-configuration-processor + true + + + \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java new file mode 100644 index 000000000..167b6019f --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java @@ -0,0 +1,307 @@ +/** + * 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; + +import java.io.InputStream; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.ArtifactDeleteFailedException; +import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.GridFSDBFileNotFoundException; +import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException; +import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException; +import org.eclipse.hawkbit.repository.model.Artifact; +import org.eclipse.hawkbit.repository.model.ExternalArtifact; +import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.hateoas.Identifiable; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Service for {@link Artifact} management operations. + * + */ +public interface ArtifactManagement { + + /** + * Creates {@link ExternalArtifact} based on given provider. + * + * @param externalRepository + * the artifact is located in + * @param urlSuffix + * of the artifact + * {@link ExternalArtifactProvider#getDefaultSuffix()} is used if + * empty. + * @param moduleId + * to assign the artifact to + * + * @return created {@link ExternalArtifact} + * + * @throws EntityNotFoundException + * if {@link SoftwareModule} with given ID does not exist + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + ExternalArtifact createExternalArtifact(@NotNull ExternalArtifactProvider externalRepository, String urlSuffix, + @NotNull Long moduleId); + + /** + * @return the total amount of local artifacts stored in the artifact + * management + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countLocalArtifactsAll(); + + /** + * @return the total amount of external artifacts stored in the artifact + * management + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countExternalArtifactsAll(); + + /** + * Persists {@link ExternalArtifactProvider} based on given properties. + * + * @param name + * of the provided + * @param description + * which is optional + * @param basePath + * of all {@link ExternalArtifact}s of the provider + * @param defaultUrlSuffix + * that is used if {@link ExternalArtifact#getUrlSuffix()} is + * empty. + * @return created {@link ExternalArtifactProvider} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + ExternalArtifactProvider createExternalArtifactProvider(@NotEmpty String name, String description, + @NotNull String basePath, String defaultUrlSuffix); + + /** + * Persists artifact binary as provided by given InputStream. assign the + * artifact in addition to given {@link SoftwareModule}. + * + * @param inputStream + * to read from for artifact binary + * @param moduleId + * to assign the new artifact to + * @param filename + * of the artifact + * @param overrideExisting + * to true if the artifact binary can be overridden + * if it already exists + * + * @return uploaded {@link LocalArtifact} + * + * @throw ArtifactUploadFailedException if upload fails + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + LocalArtifact createLocalArtifact(@NotNull InputStream inputStream, @NotNull Long moduleId, final String filename, + final boolean overrideExisting); + + /** + * Persists artifact binary as provided by given InputStream. assign the + * artifact in addition to given {@link SoftwareModule}. + * + * @param inputStream + * to read from for artifact binary + * @param moduleId + * to assign the new artifact to + * @param filename + * of the artifact + * @param overrideExisting + * 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 fails + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + LocalArtifact createLocalArtifact(@NotNull InputStream inputStream, @NotNull Long moduleId, + @NotNull String filename, final boolean overrideExisting, @NotNull String contentType); + + /** + * Persists artifact binary as provided by given InputStream. assign the + * artifact in addition to given {@link SoftwareModule}. + * + * @param stream + * to read from for artifact binary + * @param moduleId + * to assign the new artifact to + * @param filename + * of the artifact + * @param providedSha1Sum + * optional sha1 checksum to check the new file against + * @param providedMd5Sum + * optional md5 checksum to check the new file against + * @param overrideExisting + * to true if the artifact binary can be overdiden + * if it already exists + * @param contentType + * the contentType of the file + * @return uploaded {@link LocalArtifact} + * + * @throws EntityNotFoundException + * if given software module does not exist + * @throws EntityAlreadyExistsException + * if File with that name already exists in the Software Module + * @throws ArtifactUploadFailedException + * if upload fails with internal server errors + * @throws InvalidMD5HashException + * if check against provided MD5 checksum failed + * @throws InvalidSHA1HashException + * if check against provided SHA1 checksum failed + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + LocalArtifact createLocalArtifact(@NotNull InputStream stream, @NotNull Long moduleId, @NotEmpty String filename, + String providedMd5Sum, String providedSha1Sum, boolean overrideExisting, String contentType); + + /** + * Deletes {@link Artifact} based on given id. + * + * @param id + * of the {@link Artifact} that has to be deleted. + * @throws ArtifactDeleteFailedException + * if deletion failed (MongoDB is not available) + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteExternalArtifact(@NotNull Long id); + + /** + * Deletes a local artifact. + * + * @param existing + * the related local artifact + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteLocalArtifact(@NotNull LocalArtifact existing); + + /** + * Deletes {@link Artifact} based on given id. + * + * @param id + * of the {@link Artifact} that has to be deleted. + * @throws ArtifactDeleteFailedException + * if deletion failed (MongoDB is not available) + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteLocalArtifact(@NotNull Long id); + + /** + * Searches for {@link Artifact} with given {@link Identifiable}. + * + * @param id + * to search for + * @return found {@link Artifact} or null is it could not be + * found. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Artifact findArtifact(@NotNull Long id); + + /** + * Find by artifact by software module id and filename. + * + * @param filename + * file name + * @param softwareModuleId + * software module id. + * @return LocalArtifact if artifact present + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_CONTROLLER) + List findByFilenameAndSoftwareModule(@NotNull String filename, @NotNull Long softwareModuleId); + + /** + * Find all local artifact by sha1 and return the first artifact. + * + * @param sha1 + * the sha1 + * @return the first local artifact + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_CONTROLLER) + LocalArtifact findFirstLocalArtifactsBySHA1(@NotNull String sha1); + + /** + * Searches for {@link Artifact} with given file name. + * + * @param filename + * to search for + * @return found List of {@link LocalArtifact}s. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_CONTROLLER) + List findLocalArtifactByFilename(@NotNull String filename); + + /** + * Get local artifact for a base software module. + * + * @param pageReq + * Pageable + * @param swId + * software module id + * @return Page + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findLocalArtifactBySoftwareModule(@NotNull Pageable pageReq, @NotNull Long swId); + + /** + * Finds {@link SoftwareModule} by given id. + * + * @param id + * to search for + * @return the found {@link SoftwareModule}s or null if not + * found. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_CONTROLLER) + SoftwareModule findSoftwareModuleById(@NotNull Long id); + + /** + * Retrieves software module including details ( + * {@link SoftwareModule#getArtifacts()}). + * + * @param id + * parameter + * @param isDeleted + * parameter + * @return the found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModule findSoftwareModuleWithDetails(@NotNull Long id); + + /** + * Loads {@link DbArtifact} from store for given {@link LocalArtifact}. + * + * @param artifact + * to search for + * @return loaded {@link DbArtifact} + * + * @throws GridFSDBFileNotFoundException + * if file could not be found in store + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DOWNLOAD_ARTIFACT + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.HAS_CONTROLLER_DOWNLOAD) + DbArtifact loadLocalArtifactBinary(@NotNull LocalArtifact artifact); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/Constants.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/Constants.java new file mode 100644 index 000000000..5dcb26638 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/Constants.java @@ -0,0 +1,76 @@ +/** + * 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; + +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; + +/** + * Repository API constants. + * + */ +public final class Constants { + /** + * {@link SoftwareModuleType#getKey()} of a {@link SoftwareModuleType} + * generated by repository for every new account for Firmware/Operating + * System. + */ + public static final String SMT_DEFAULT_OS_KEY = "os"; + /** + * {@link SoftwareModuleType#getKey()} of a {@link SoftwareModuleType} + * generated by repository for every new account for applications. + */ + public static final String SMT_DEFAULT_APP_KEY = "application"; + + /** + * {@link SoftwareModuleType#getName()} of a {@link SoftwareModuleType} + * generated by repository for every new account for "Firmware/Operating + * System" . + */ + public static final String SMT_DEFAULT_OS_NAME = "OS"; + /** + * {@link SoftwareModuleType#getName()} of a {@link SoftwareModuleType} + * generated by repository for every new account for "applications/apps". + */ + public static final String SMT_DEFAULT_APP_NAME = "Application"; + + /** + * {@link DistributionSetType#getKey()} of a {@link DistributionSetType} + * generated by repository for every new account that includes + * {@link #SMT_DEFAULT_OS_KEY} as mandatory module and optional + * {@link #SMT_DEFAULT_APP_KEY}s. + */ + public static final String DST_DEFAULT_OS_WITH_APPS_KEY = "os_app"; + + /** + * {@link DistributionSetType#getName()} of a {@link DistributionSetType} + * generated by repository for every new account that includes + * {@link #SMT_DEFAULT_OS_KEY} as mandatory module and optional + * {@link #SMT_DEFAULT_APP_KEY}s. + */ + public static final String DST_DEFAULT_OS_WITH_APPS_NAME = "OS with app(s)"; + + /** + * {@link DistributionSetType#getKey()} of a {@link DistributionSetType} + * generated by repository for every new account that includes only + * {@link #SMT_DEFAULT_OS_KEY} as mandatory module. + */ + public static final String DST_DEFAULT_OS_ONLY_KEY = "os"; + + /** + * {@link DistributionSetType#getName()} of a {@link DistributionSetType} + * generated by repository for every new account that includes only + * {@link #SMT_DEFAULT_OS_KEY} as mandatory module. + */ + public static final String DST_DEFAULT_OS_ONLY_NAME = "OS only"; + + private Constants() { + // Utility class. + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java new file mode 100644 index 000000000..e5dcb8f74 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java @@ -0,0 +1,289 @@ +/** + * 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; + +import java.net.URI; +import java.util.List; +import java.util.Map; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException; +import org.eclipse.hawkbit.repository.exception.ToManyStatusEntriesException; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.security.access.prepost.PreAuthorize; + +import com.google.common.eventbus.EventBus; + +/** + * Service layer for all operations of the DDI API (with access permissions only + * for the controller). + * + */ +public interface ControllerManagement { + + /** + * Adds an {@link ActionStatus} for a cancel {@link Action} including + * potential state changes for the target and the {@link Action} itself. + * + * @param actionStatus + * to be added + * @return the persisted {@link Action} + * + * @throws EntityAlreadyExistsException + * if a given entity already exists + * + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Action addCancelActionStatus(@NotNull ActionStatus actionStatus); + + /** + * Sends the download progress and notifies the {@link EventBus} with a + * {@link DownloadProgressEvent}. + * + * @param statusId + * the ID of the {@link ActionStatus} + * @param requestedBytes + * requested bytes of the request + * @param shippedBytesSinceLast + * since the last report + * @param shippedBytesOverall + * for the {@link ActionStatus} + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + void downloadProgress(Long statusId, Long requestedBytes, Long shippedBytesSinceLast, Long shippedBytesOverall); + + /** + * Simple addition of a new {@link ActionStatus} entry to the {@link Action} + * . No state changes. + * + * @param statusMessage + * to add to the action + * + * @return create {@link ActionStatus} entity + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + ActionStatus addInformationalActionStatus(@NotNull ActionStatus statusMessage); + + /** + * Adds an {@link ActionStatus} entry for an update {@link Action} including + * potential state changes for the target and the {@link Action} itself. + * + * @param actionStatus + * to be added + * @return the updated {@link Action} + * + * @throws EntityAlreadyExistsException + * if a given entity already exists + * @throws ToManyStatusEntriesException + * if more than the allowed number of status entries are + * inserted + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Action addUpdateActionStatus(@NotNull ActionStatus actionStatus); + + /** + * Retrieves all {@link Action}s which are active and assigned to a + * {@link Target}. + * + * @param target + * the target to retrieve the actions from + * @return a list of actions assigned to given target which are active + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + List findActionByTargetAndActive(@NotNull Target target); + + /** + * Get the {@link Action} entity for given actionId with all lazy + * attributes. + * + * @param actionId + * to be id of the action + * @return the corresponding {@link Action} + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Action findActionWithDetails(@NotNull Long actionId); + + /** + * register new target in the repository (plug-and-play). + * + * @param controllerId + * reference + * @param address + * the client IP address of the target, might be {@code null} + * @return target reference + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Target findOrRegisterTargetIfItDoesNotexist(@NotEmpty String controllerId, URI address); + + /** + * Retrieves all {@link SoftwareModule}s which are assigned to the given + * {@link DistributionSet}. + * + * @param distributionSet + * the distribution set which should be assigned to the returned + * {@link SoftwareModule}s + * @return a list of {@link SoftwareModule}s assigned to given + * {@code distributionSet} + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + List findSoftwareModulesByDistributionSet(@NotNull DistributionSet distributionSet); + + /** + * Retrieves last {@link Action} for a download of an artifact of given + * module and target. + * + * @param controllerId + * to look for + * @param module + * that should be assigned to the target + * @return last {@link Action} for given combination + * + * @throws EntityNotFoundException + * if action for given combination could not be found + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Action getActionForDownloadByTargetAndSoftwareModule(@NotEmpty String controllerId, @NotNull SoftwareModule module); + + /** + * @return current {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}. + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + String getPollingTime(); + + /** + * An direct access to the security token of an + * {@link Target#getSecurityToken()} without authorization. This is + * necessary to be able to access the security-token without any + * security-context information because the security-token is used for + * authentication. + * + * @param controllerId + * the ID of the controller to retrieve the security token for + * @return the security context of the target, in case no target exists for + * the given controllerId {@code null} is returned + */ + String getSecurityTokenByControllerId(@NotEmpty String controllerId); + + /** + * Checks if a given target has currently or has even been assigned to the + * given artifact through the action history list. This can e.g. indicate if + * a target is allowed to download a given artifact because it has currently + * assigned or had ever been assigned to the target and so it's visible to a + * specific target e.g. for downloading. + * + * @param controllerId + * the ID of the target to check + * @param localArtifact + * the artifact to verify if the given target had even been + * assigned to + * @return {@code true} if the given target has currently or had ever a + * relation to the given artifact through the action history, + * otherwise {@code false} + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + boolean hasTargetArtifactAssigned(@NotNull String controllerId, @NotNull LocalArtifact localArtifact); + + /** + * Registers retrieved status for given {@link Target} and {@link Action} if + * it does not exist yet. + * + * @param action + * to the handle status for + * @param message + * for the status + * @return the update action in case the status has been changed to + * {@link Status#RETRIEVED} + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Action registerRetrieved(@NotNull Action action, String message); + + /** + * Updates attributes of the controller. + * + * @param controllerId + * to update + * @param attributes + * to insert + * + * @return updated {@link Target} + * + * @throws EntityNotFoundException + * if target that has to be updated could not be found + * @throws ToManyAttributeEntriesException + * if maximum + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map attributes); + + /** + * Refreshes the time of the last time the controller has been connected to + * the server. + * + * @param controllerId + * of the target to to update + * @param address + * the client address of the target, might be {@code null} + * @return the updated target + * + * @throws EntityNotFoundException + * if target with given ID could not be found + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Target updateLastTargetQuery(@NotEmpty String controllerId, URI address); + + /** + * Refreshes the time of the last time the controller has been connected to + * the server. + * + * @param target + * to update + * @param address + * the client address of the target, might be {@code null} + * @return the updated target + * + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + TargetInfo updateLastTargetQuery(@NotNull TargetInfo target, @NotNull URI address); + + /** + * Update selective the target status of a given {@code target}. + * + * @param targetInfo + * the target to update the target status + * @param status + * the status to be set of the target. Might be {@code null} if + * the target status should not be updated + * @param lastTargetQuery + * the last target query to be set of the target. Might be + * {@code null} if the target lastTargetQuery should not be + * updated + * @param address + * the client address of the target, might be {@code null} + * @return the updated TargetInfo + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + TargetInfo updateTargetStatus(@NotNull TargetInfo targetInfo, TargetUpdateStatus status, Long lastTargetQuery, + URI address); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java new file mode 100644 index 000000000..270de3e74 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java @@ -0,0 +1,510 @@ +/** + * 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; + +import java.util.Collection; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.Action.ActionType; +import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.ActionWithStatusCount; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetWithActionType; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * A DeploymentManagement service provides operations for the deployment of + * {@link DistributionSet}s to {@link Target}s. + * + */ +public interface DeploymentManagement { + + /** + * method assigns the {@link DistributionSet} to all {@link Target}s. + * + * @param pset + * {@link DistributionSet} which is assigned to the + * {@link Target}s + * @param targets + * the {@link Target}s which should obtain the + * {@link DistributionSet} + * + * @return the changed targets + * + * @throw IncompleteDistributionSetException if mandatory + * {@link SoftwareModuleType} are not assigned as define by the + * {@link DistributionSetType}. * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) + DistributionSetAssignmentResult assignDistributionSet(@NotNull DistributionSet pset, + @NotEmpty List targets); + + /** + * method assigns the {@link DistributionSet} to all {@link Target}s by + * their IDs with a specific {@link ActionType} and {@code forcetime}. + * + * @param dsID + * the ID of the distribution set to assign + * @param actionType + * the type of the action to apply on the assignment + * @param forcedTimestamp + * the time when the action should be forced, only necessary for + * {@link ActionType#TIMEFORCED} + * @param targetIDs + * the IDs of the target to assign the distribution set + * @return the assignment result + * + * @throw IncompleteDistributionSetException if mandatory + * {@link SoftwareModuleType} are not assigned as define by the + * {@link DistributionSetType}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) + DistributionSetAssignmentResult assignDistributionSet(@NotNull final Long dsID, final ActionType actionType, + final long forcedTimestamp, @NotEmpty final String... targetIDs); + + /** + * method assigns the {@link DistributionSet} to all {@link Target}s by + * their IDs with a specific {@link ActionType} and {@code forcetime}. + * + * @param dsID + * the ID of the distribution set to assign + * @param targets + * a list of all targets and their action type + * @return the assignment result + * + * @throw IncompleteDistributionSetException if mandatory + * {@link SoftwareModuleType} are not assigned as define by the + * {@link DistributionSetType}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) + DistributionSetAssignmentResult assignDistributionSet(@NotNull Long dsID, + @NotEmpty Collection targets); + + /** + * method assigns the {@link DistributionSet} to all {@link Target}s by + * their IDs with a specific {@link ActionType} and {@code forcetime}. + * + * @param dsID + * the ID of the distribution set to assign + * @param targets + * a list of all targets and their action type + * @param rollout + * the rollout for this assignment + * @param rolloutGroup + * the rollout group for this assignment + * @return the assignment result + * + * @throw IncompleteDistributionSetException if mandatory + * {@link SoftwareModuleType} are not assigned as define by the + * {@link DistributionSetType}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) + DistributionSetAssignmentResult assignDistributionSet(@NotNull Long dsID, + @NotEmpty Collection targets, Rollout rollout, RolloutGroup rolloutGroup); + + /** + * method assigns the {@link DistributionSet} to all {@link Target}s by + * their IDs. + * + * @param dsID + * {@link DistributionSet} which is assigned to the + * {@link Target}s + * @param targetIDs + * IDs of the {@link Target}s which should obtain the + * {@link DistributionSet} + * + * @return the changed targets + * + * @throws EntityNotFoundException + * if {@link DistributionSet} does not exist. + * + * @throw IncompleteDistributionSetException if mandatory + * {@link SoftwareModuleType} are not assigned as define by the + * {@link DistributionSetType}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) + DistributionSetAssignmentResult assignDistributionSet(@NotNull Long dsID, @NotEmpty String... targetIDs); + + /** + * Cancels given {@link Action} for given {@link Target}. The method will + * immediately add a {@link Status#CANCELED} status to the action. However, + * it might be possible that the controller will continue to work on the + * cancellation. + * + * @param action + * to be canceled + * @param target + * for which the action needs cancellation + * + * @return generated {@link Action} or null if not active on + * given {@link Target}. + * @throws CancelActionNotAllowedException + * in case the given action is not active or is already a cancel + * action + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + Action cancelAction(@NotNull Action action, @NotNull Target target); + + /** + * counts all actions associated to a specific target. + * + * @param rsqlParam + * rsql query string + * @param target + * the target associated to the actions to count + * @return the count value of found actions associated to the target + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Long countActionsByTarget(@NotNull String rsqlParam, @NotNull Target target); + + /** + * @return the total amount of stored action status + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Long countActionStatusAll(); + + /** + * @return the total amount of stored actions + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Long countActionsAll(); + + /** + * counts all actions associated to a specific target. + * + * @param target + * the target associated to the actions to count + * @return the count value of found actions associated to the target + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Long countActionsByTarget(@NotNull Target target); + + /** + * Creates an action entry into the action repository. In case of existing + * scheduled actions the scheduled actions gets canceled. A scheduled action + * is created in-active. + * + * @param targets + * the targets to create scheduled actions for + * @param distributionSet + * the distribution set for the actions + * @param actionType + * the action type for the action + * @param forcedTime + * the forcedTime of the action + * @param rollout + * the roll out for this action + * @param rolloutGroup + * the roll out group for this action + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + void createScheduledAction(@NotEmpty Collection targets, @NotNull DistributionSet distributionSet, + @NotNull ActionType actionType, Long forcedTime, @NotNull Rollout rollout, + @NotNull RolloutGroup rolloutGroup); + + /** + * Get the {@link Action} entity for given actionId. + * + * @param actionId + * to be id of the action + * @return the corresponding {@link Action} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Action findAction(@NotNull Long actionId); + + /** + * Retrieves all actions for a specific rollout and in a specific status. + * + * @param rollout + * the rollout the actions beglong to + * @param actionStatus + * the status of the actions + * @return the actions referring a specific rollout an in a specific status + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findActionsByRolloutAndStatus(@NotNull Rollout rollout, @NotNull Action.Status actionStatus); + + /** + * Retrieving all actions referring to a given rollout with a specific + * action as parent reference and a specific status. + * + * Finding all actions of a specific rolloutgroup parent relation. + * + * @param rollout + * the rollout the actions belong to + * @param rolloutGroupParent + * 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 + * rollout group in a specific status + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findActionsByRolloutGroupParentAndStatus(@NotNull Rollout rollout, + @NotNull RolloutGroup rolloutGroupParent, @NotNull Action.Status actionStatus); + + /** + * Retrieves all {@link Action}s of a specific target. + * + * @param pageable + * pagination parameter + * @param target + * of which the actions have to be searched + * @return a paged list of actions associated with the given target + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Slice findActionsByTarget(@NotNull Pageable pageable, @NotNull Target target); + + /** + * Retrieves all {@link Action}s from repository. + * + * @param pageable + * pagination parameter + * @return a paged list of {@link Action}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Slice findActionsAll(@NotNull Pageable pageable); + + /** + * Retrieves all {@link Action} which assigned to a specific + * {@link DistributionSet}. + * + * @param pageable + * the page request parameter for paging and sorting the result + * @param distributionSet + * the distribution set which should be assigned to the actions + * in the result + * @return a list of {@link Action} which are assigned to a specific + * {@link DistributionSet} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Slice findActionsByDistributionSet(@NotNull Pageable pageable, @NotNull DistributionSet distributionSet); + + /** + * Retrieves all {@link Action}s assigned to a specific {@link Target} and a + * given specification. + * + * @param rsqlParam + * rsql query string + * @param target + * the target which must be assigned to the actions + * @param pageable + * the page request + * @return a slice of actions assigned to the specific target and the + * specification + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Slice findActionsByTarget(@NotNull String rsqlParam, @NotNull Target target, @NotNull Pageable pageable); + + /** + * Retrieves all {@link Action}s of a specific target ordered by action ID. + * + * @param target + * the target associated with the actions + * @return a list of actions associated with the given target ordered by + * action ID + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findActionsByTarget(@NotNull Target target); + + /** + * Retrieves all {@link Action}s which are referring the given + * {@link Target}. + * + * @param foundTarget + * the target to find actions for + * @param pageable + * the pageable request to limit, sort the actions + * @return a slice of actions found for a specific target + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Slice findActionsByTarget(@NotNull Target foundTarget, @NotNull Pageable pageable); + + /** + * Retrieves all the {@link ActionStatus} entries of the given + * {@link Action} and {@link Target}. + * + * @param pageReq + * pagination parameter + * @param action + * to be filtered on + * @param withMessages + * to true if {@link ActionStatus#getMessages()} + * need to be fetched. + * @return the corresponding {@link Page} of {@link ActionStatus} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Page findActionStatusByAction(@NotNull Pageable pageReq, @NotNull Action action); + + /** + * Retrieves all {@link ActionStatus} inclusive their messages by a specific + * {@link Action}. + * + * @param pageable + * the page request parameter for paging and sorting the result + * @param action + * the {@link Action} to retrieve the {@link ActionStatus} from + * @return a page of {@link ActionStatus} by a speciifc {@link Action} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Page findActionStatusByActionWithMessages(@NotNull Pageable pageable, @NotNull Action action); + + /** + * Retrieves all {@link Action}s of a specific target ordered by action ID. + * + * @param target + * the target associated with the actions + * @return a list of actions associated with the given target ordered by + * action ID + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findActionsWithStatusCountByTargetOrderByIdDesc(@NotNull Target target); + + /** + * Get the {@link Action} entity for given actionId with all lazy attributes + * (i.e. distributionSet, target, target.assignedDs). + * + * @param actionId + * to be id of the action + * @return the corresponding {@link Action} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Action findActionWithDetails(@NotNull Long actionId); + + /** + * Retrieves all active {@link Action}s of a specific target ordered by + * action ID. + * + * @param pageable + * the pagination parameter + * @param target + * the target associated with the actions + * @return a paged list of actions associated with the given target + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Page findActiveActionsByTarget(@NotNull Pageable pageable, @NotNull Target target); + + /** + * Retrieves all active {@link Action}s of a specific target ordered by + * action ID. + * + * @param target + * the target associated with the actions + * @return a list of actions associated with the given target + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findActiveActionsByTarget(@NotNull Target target); + + /** + * Retrieves all inactive {@link Action}s of a specific target ordered by + * action ID. + * + * @param pageable + * the pagination parameter + * @param target + * the target associated with the actions + * @return a paged list of actions associated with the given target + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Page findInActiveActionsByTarget(@NotNull Pageable pageable, @NotNull Target target); + + /** + * Retrieves all inactive {@link Action}s of a specific target ordered by + * action ID. + * + * @param target + * the target associated with the actions + * @return a list of actions associated with the given target + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findInActiveActionsByTarget(@NotNull Target target); + + /** + * Force cancels given {@link Action} for given {@link Target}. Force + * canceling means that the action is marked as canceled on the SP server + * and a cancel request is sent to the target. But however it's not tracked, + * if the targets handles the cancel request or not. + * + * @param action + * to be canceled + * @param target + * for which the action needs cancellation + * + * @return generated {@link Action} or null if not active on + * {@link Target}. + * @throws CancelActionNotAllowedException + * in case the given action is not active + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + Action forceQuitAction(@NotNull Action action); + + /** + * Updates a {@link Action} and forces the {@link Action} if it's not + * already forced. + * + * @param targetId + * the ID of the target + * @param actionId + * the ID of the action + * @return the updated or the found {@link Action} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + Action forceTargetAction(@NotNull Long actionId); + + /** + * Starting an action which is scheduled, e.g. in case of roll out a + * scheduled action must be started now. + * + * @param action + * the action to start now. + * @return the action which has been started + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Action startScheduledAction(@NotNull Action action); + + /** + * All {@link ActionStatus} entries in the repository. + * + * @param pageable + * the pagination parameter + * @return {@link Page} of {@link ActionStatus} entries + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Page findActionStatusAll(@NotNull Pageable pageable); +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetAssignmentResult.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetAssignmentResult.java similarity index 99% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetAssignmentResult.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetAssignmentResult.java index 85e707652..f21763883 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetAssignmentResult.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetAssignmentResult.java @@ -51,11 +51,6 @@ public class DistributionSetAssignmentResult extends AssignmentResult { this.actions = actions; this.targetManagement = targetManagement; } - - @Override - public List getAssignedEntity() { - return targetManagement.findTargetByControllerID(assignedTargets); - } /** * @return the actionIds @@ -64,4 +59,9 @@ public class DistributionSetAssignmentResult extends AssignmentResult { return actions; } + @Override + public List getAssignedEntity() { + return targetManagement.findTargetByControllerID(assignedTargets); + } + } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java new file mode 100644 index 000000000..a2e7e5213 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java @@ -0,0 +1,598 @@ +/** + * 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; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.DistributionSetCreationFailedMissingMandatoryModuleException; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetFilter; +import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.Tag; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Management service for {@link DistributionSet}s. + * + */ +public interface DistributionSetManagement { + + // TODO rename/document the whole with details thing (document what the + // details are and maybe find a better name, e.g. with dependencies?) + + /** + * Assigns {@link SoftwareModule} to existing {@link DistributionSet}. + * + * @param ds + * to assign and update + * @param softwareModules + * to get assigned + * @return the updated {@link DistributionSet}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet assignSoftwareModules(@NotNull DistributionSet ds, Set softwareModules); + + /** + * Assign a {@link DistributionSetTag} assignment to given + * {@link DistributionSet}s. + * + * @param dsIds + * to assign for + * @param tag + * to assign + * @return list of assigned ds + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List assignTag(@NotEmpty Collection dsIds, @NotNull DistributionSetTag tag); + + /** + * Count all {@link DistributionSet}s in the repository that are not marked + * as deleted. + * + * @return number of {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countDistributionSetsAll(); + + /** + * Count all {@link DistributionSet}s in the repository that are not marked + * as deleted. + * + * @param type + * to look for + * + * @return number of {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countDistributionSetsByType(@NotNull DistributionSetType type); + + /** + * @return number of {@link DistributionSetType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countDistributionSetTypesAll(); + + /** + * Creates a new {@link DistributionSet}. + * + * @param dSet + * {@link DistributionSet} to be created + * @return the new persisted {@link DistributionSet} + * + * @throws EntityAlreadyExistsException + * if a given entity already exists + * @throws DistributionSetCreationFailedMissingMandatoryModuleException + * is {@link DistributionSet} does not contain mandatory + * {@link SoftwareModule}s. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + DistributionSet createDistributionSet(@NotNull DistributionSet dSet); + + /** + * creates a list of distribution set meta data entries. + * + * @param metadata + * the meta data entries to create or update + * @return the updated or created distribution set meta data entries + * @throws EntityAlreadyExistsException + * in case one of the meta data entry already exists for the + * specific key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List createDistributionSetMetadata(@NotEmpty Collection metadata); + + /** + * creates or updates a single distribution set meta data entry. + * + * @param metadata + * the meta data entry to create or update + * @return the updated or created distribution set meta data entry + * @throws EntityAlreadyExistsException + * in case the meta data entry already exists for the specific + * key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetMetadata createDistributionSetMetadata(@NotNull DistributionSetMetadata metadata); + + /** + * Creates multiple {@link DistributionSet}s. + * + * @param distributionSets + * to be created + * @return the new {@link DistributionSet}s + * @throws EntityAlreadyExistsException + * if a given entity already exists + * @throws DistributionSetCreationFailedMissingMandatoryModuleException + * is {@link DistributionSet} does not contain mandatory + * {@link SoftwareModule}s. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createDistributionSets(@NotNull Collection distributionSets); + + /** + * Creates new {@link DistributionSetType}. + * + * @param type + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + DistributionSetType createDistributionSetType(@NotNull DistributionSetType type); + + /** + * Creates multiple {@link DistributionSetType}s. + * + * @param types + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createDistributionSetTypes(@NotNull Collection types); + + /** + *

+ * {@link DistributionSet} can be deleted/erased from the repository if they + * have never been assigned to any {@link UpdateAction} or {@link Target}. + *

+ * + *

+ * If they have been assigned that need to be marked as deleted which as a + * result means that they cannot be assigned anymore to any targets. (define + * e.g. findByDeletedFalse()) + *

+ * + * @param set + * to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteDistributionSet(@NotNull DistributionSet set); + + /** + * Deleted {@link DistributionSet}s by their IDs. That is either a soft + * delete of the entities have been linked to an {@link UpdateAction} before + * or a hard delete if not. + * + * @param distributionSetIDs + * to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteDistributionSet(@NotEmpty Long... distributionSetIDs); + + /** + * deletes a distribution set meta data entry. + * + * @param id + * the ID of the distribution set meta data to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + void deleteDistributionSetMetadata(@NotNull final DistributionSet distributionSet, @NotNull final String key); + + /** + * Deletes or mark as delete in case the type is in use. + * + * @param type + * to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteDistributionSetType(@NotNull DistributionSetType type); + + /** + * retrieves the distribution set for a given action. + * + * @param action + * the action associated with the distribution set + * @return the distribution set which is associated with the action + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetByAction(@NotNull Action action); + + /** + * Find {@link DistributionSet} based on given ID without details, e.g. + * {@link DistributionSet#getAgentHub()}. + * + * @param distid + * to look for. + * @return {@link DistributionSet} or null if it does not exist + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetById(@NotNull Long distid); + + /** + * Find {@link DistributionSet} based on given ID including (lazy loaded) + * details, e.g. {@link DistributionSet#getAgentHub()}. + * + * Note: for performance reasons it is recommended to use + * {@link #findDistributionSetById(Long)} if details are not necessary. + * + * @param distid + * to look for. + * @return {@link DistributionSet} or null if it does not exist + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetByIdWithDetails(@NotNull Long distid); + + /** + * Find distribution set by name and version. + * + * @param distributionName + * name of {@link DistributionSet}; case insensitive + * @param version + * version of {@link DistributionSet} + * @return the page with the found {@link DistributionSet} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetByNameAndVersion(@NotEmpty String distributionName, @NotEmpty String version); + + /** + * finds all meta data by the given distribution set id. + * + * @param distributionSetId + * the distribution set id to retrieve the meta data from + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given distribution + * set id + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId, + @NotNull Pageable pageable); + + /** + * finds all meta data by the given distribution set id. + * + * @param distributionSetId + * the distribution set id to retrieve the meta data from + * @param rsqlParam + * rsql query string + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given distribution + * set id + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId, + @NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * Retrieves {@link DistributionSet} List for overview purposes (no + * {@link SoftwareModule}s and {@link DistributionSetTag}s). + * + * Please use {@link #findDistributionSetListWithDetails(Iterable)} if + * details are required. + * + * @param dist + * List of {@link DistributionSet} IDs to be found + * @return the found {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List findDistributionSetsAll(Collection dist); + + // TODO discuss: use enum instead of the true,false,null switch ? + /** + * finds all {@link DistributionSet}s. + * + * @param pageReq + * the pagination parameter + * @param deleted + * if TRUE, {@link DistributionSet}s marked as deleted are + * returned. If FALSE, on {@link DistributionSet}s with + * {@link DistributionSet#isDeleted()} == FALSE are returned. + * null if both are to be returned + * @param complete + * to true for returning only completed distribution + * sets or false for only incomplete ones nor + * null to return both. + * @param complete + * set to if false incomplete DS should also be + * shown. + * + * + * @return all found {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsByDeletedAndOrCompleted(@NotNull Pageable pageReq, Boolean deleted, + Boolean complete); + + /** + * finds all {@link DistributionSet}s. + * + * @param rsqlParam + * rsql query string + * @param pageReq + * the pagination parameter + * @param deleted + * if TRUE, {@link DistributionSet}s marked as deleted are + * returned. If FALSE, on {@link DistributionSet}s with + * {@link DistributionSet#isDeleted()} == FALSE are returned. + * null if both are to be returned + * @return all found {@link DistributionSet}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsAll(@NotNull String rsqlParam, @NotNull Pageable pageReq, + Boolean deleted); + + /** + * method retrieves all {@link DistributionSet}s from the repository in the + * following order: + *

+ * 1) {@link DistributionSet}s which have the given {@link Target} as + * {@link TargetStatus#getInstalledDistributionSet()} + *

+ * 2) {@link DistributionSet}s which have the given {@link Target} as + * {@link Target#getAssignedDistributionSet()} + *

+ * 3) {@link DistributionSet}s which have no connection to the given + * {@link Target} ordered by ID of the DistributionSet. + * + * @param pageable + * the page request to page the result set * + * @param distributionSetFilterBuilder + * has details of filters to be applied + * @param assignedOrInstalled + * the controllerID of the Target to be ordered by + * @return + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsAllOrderedByLinkTarget(@NotNull Pageable pageable, + @NotNull DistributionSetFilterBuilder distributionSetFilterBuilder, @NotEmpty String assignedOrInstalled); + + /** + * retrieves {@link DistributionSet}s by filtering on the given parameters. + * + * @param pageable + * page parameter + * @param distributionSetFilter + * has details of filters to be applied. + * @return the page of found {@link DistributionSet} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsByFilters(@NotNull Pageable pageable, + @NotNull DistributionSetFilter distributionSetFilter); + + /** + * @param id + * as {@link DistributionSetType#getId()} + * @return {@link DistributionSetType} if found or null if not + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetType findDistributionSetTypeById(@NotNull Long id); + + /** + * @param key + * as {@link DistributionSetType#getKey()} + * @return {@link DistributionSetType} if found or null if not + */ + + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetType findDistributionSetTypeByKey(@NotNull String key); + + /** + * @param name + * as {@link DistributionSetType#getName()} + * @return {@link DistributionSetType} if found or null if not + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetType findDistributionSetTypeByName(@NotEmpty String name); + + /** + * @param pageable + * parameter + * @return all {@link DistributionSetType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetTypesAll(@NotNull Pageable pageable); + + /** + * Generic predicate based query for {@link DistributionSetType}. + * + * @param rsqlParam + * rsql query string + * @param pageable + * parameter for paging + * + * @return the found {@link SoftwareModuleType}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetTypesAll(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * finds a single distribution set meta data by its id. + * + * @param id + * the id of the distribution set meta data containing the meta + * data key and the ID of the distribution set + * @return the found DistributionSetMetadata or {@code null} if not exits + * @throws EntityNotFoundException + * in case the meta data does not exists for the given key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetMetadata findOne(@NotNull DistributionSet distributionSet, @NotNull String key); + + /** + * Checks if a {@link DistributionSet} is currently in use by a target in + * the repository. + * + * @param distributionSet + * to check + * + * @return true if in use + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + boolean isDistributionSetInUse(@NotNull DistributionSet distributionSet); + + /** + * {@link Entity} based method call for + * {@link #toggleTagAssignment(Collection, String)}. + * + * @param sets + * to toggle for + * @param tag + * to toggle + * @return {@link DistributionSetTagAssignmentResult} with all meta data of + * the assignment outcome. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection sets, + @NotNull DistributionSetTag tag); + + /** + * Toggles {@link DistributionSetTag} assignment to given + * {@link DistributionSet}s by means that if some (or all) of the targets in + * the list have the {@link Tag} not yet assigned, they will be. If all of + * theme have the tag already assigned they will be removed instead. + * + * @param dsIds + * to toggle for + * @param tagName + * to toggle + * @return {@link DistributionSetTagAssignmentResult} with all meta data of + * the assignment outcome. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection dsIds, @NotNull String tagName); + + /** + * Unassign all {@link DistributionSet} from a given + * {@link DistributionSetTag} . + * + * @param tag + * to unassign all ds + * @return list of unassigned ds + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List unAssignAllDistributionSetsByTag(@NotNull DistributionSetTag tag); + + /** + * Unassigns a {@link SoftwareModule} form an existing + * {@link DistributionSet}. + * + * @param ds + * to get unassigned form + * @param softwareModule + * to get unassigned + * @return the updated {@link DistributionSet}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet unassignSoftwareModule(@NotNull DistributionSet ds, @NotNull SoftwareModule softwareModule); + + /** + * Unassign a {@link DistributionSetTag} assignment to given + * {@link DistributionSet}. + * + * @param dsId + * to unassign for + * @param distributionSetTag + * to unassign + * @return the unassigned ds or if no ds is unassigned + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet unAssignTag(@NotNull Long dsId, @NotNull DistributionSetTag distributionSetTag); + + /** + * Updates existing {@link DistributionSet}. + * + * @param ds + * to update + * @return the saved {@link Entity}. + * @throws NullPointerException + * of {@link DistributionSet#getId()} is null + * @throw DataDependencyViolationException in case of illegal update + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet updateDistributionSet(@NotNull DistributionSet ds); + + /** + * updates a distribution set meta data value if corresponding entry exists. + * + * @param metadata + * the meta data entry to be updated + * @return the updated meta data entry + * @throws EntityNotFoundException + * in case the meta data entry does not exists and cannot be + * updated + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetMetadata updateDistributionSetMetadata(@NotNull DistributionSetMetadata metadata); + + /** + * Updates existing {@link DistributionSetType}. However, keep in mind that + * is not possible to change the {@link DistributionSetTypeElement}s while + * the DS type is already in use. + * + * @param dsType + * to update + * @return updated {@link Entity} + * + * @throws EntityReadOnlyException + * if use tries to change the {@link DistributionSetTypeElement} + * s while the DS type is already in use. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetType updateDistributionSetType(@NotNull DistributionSetType dsType); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/EntityFactory.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/EntityFactory.java new file mode 100644 index 000000000..87919729e --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/EntityFactory.java @@ -0,0 +1,355 @@ +/** + * 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; + +import java.util.Collection; +import java.util.concurrent.TimeUnit; + +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.BaseEntity; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetFilterQuery; +import org.eclipse.hawkbit.repository.model.TargetTag; +import org.hibernate.validator.constraints.NotEmpty; + +/** + * central {@link BaseEntity} generation service. Objects are created but not + * persisted. + * + */ +public interface EntityFactory { + + /** + * Generates an empty {@link Action} without persisting it. + * + * @return {@link Action} object + */ + Action generateAction(); + + /** + * Generates an empty {@link ActionStatus} object without persisting it. + * + * @return {@link ActionStatus} object + */ + ActionStatus generateActionStatus(); + + /** + * Generates an {@link ActionStatus} object without persisting it. + * + * @param action + * the {@link ActionStatus} belongs to. + * @param status + * as reflected by this {@link ActionStatus}. + * @param occurredAt + * time in {@link TimeUnit#MILLISECONDS} GMT when the status + * change happened. + * + * @return {@link ActionStatus} object + */ + ActionStatus generateActionStatus(Action action, Status status, Long occurredAt); + + /** + * Generates an {@link ActionStatus} object without persisting it. + * + * @param action + * the {@link ActionStatus} belongs to. + * @param status + * as reflected by this {@link ActionStatus}. + * @param occurredAt + * time in {@link TimeUnit#MILLISECONDS} GMT when the status + * change happened. + * @param messages + * optional comments + * + * @return {@link ActionStatus} object + */ + ActionStatus generateActionStatus(Action action, final Status status, Long occurredAt, + final Collection messages); + + /** + * Generates an {@link ActionStatus} object without persisting it. + * + * @param action + * the {@link ActionStatus} belongs to. + * @param status + * as reflected by this {@link ActionStatus}. + * @param occurredAt + * time in {@link TimeUnit#MILLISECONDS} GMT when the status + * change happened. + * @param message + * optional comment + * + * @return {@link ActionStatus} object + */ + ActionStatus generateActionStatus(Action action, Status status, Long occurredAt, final String message); + + /** + * Generates an empty {@link DistributionSet} without persisting it. + * + * @return {@link DistributionSet} object + */ + DistributionSet generateDistributionSet(); + + /** + * Generates an {@link DistributionSet} without persisting it. + * + * @param name + * {@link DistributionSet#getName()} + * @param version + * {@link DistributionSet#getVersion()} + * @param description + * {@link DistributionSet#getDescription()} + * @param type + * {@link DistributionSet#getType()} + * @param moduleList + * {@link DistributionSet#getModules()} + * + * @return {@link DistributionSet} object + */ + DistributionSet generateDistributionSet(String name, String version, String description, DistributionSetType type, + Collection moduleList); + + /** + * Generates an empty {@link DistributionSetMetadata} element without + * persisting it. + * + * @return {@link DistributionSetMetadata} object + */ + DistributionSetMetadata generateDistributionSetMetadata(); + + /** + * Generates an {@link DistributionSetMetadata} element without persisting + * it. + * + * @param distributionSet + * {@link DistributionSetMetadata#getDistributionSet()} + * @param key + * {@link DistributionSetMetadata#getKey()} + * @param value + * {@link DistributionSetMetadata#getValue()} + * + * @return {@link DistributionSetMetadata} object + */ + DistributionSetMetadata generateDistributionSetMetadata(DistributionSet distributionSet, String key, String value); + + /** + * Generates an empty {@link DistributionSetTag} without persisting it. + * + * @return {@link DistributionSetTag} object + */ + DistributionSetTag generateDistributionSetTag(); + + /** + * Generates a {@link DistributionSetTag} without persisting it. + * + * @param name + * of the tag + * @return {@link DistributionSetTag} object + */ + DistributionSetTag generateDistributionSetTag(String name); + + /** + * Generates a {@link DistributionSetTag} without persisting it. + * + * @param name + * of the tag + * @param description + * of the tag + * @param colour + * of the tag + * @return {@link DistributionSetTag} object + */ + DistributionSetTag generateDistributionSetTag(String name, String description, String colour); + + /** + * Generates an empty {@link DistributionSetType} without persisting it. + * + * @return {@link DistributionSetType} object + */ + DistributionSetType generateDistributionSetType(); + + /** + * Generates a {@link DistributionSetType} without persisting it. + * + * @param key + * {@link DistributionSetType#getKey()} + * @param name + * {@link DistributionSetType#getName()} + * @param description + * {@link DistributionSetType#getDescription()} + * + * @return {@link DistributionSetType} object + */ + DistributionSetType generateDistributionSetType(String key, String name, String description); + + /** + * Generates an empty {@link Rollout} without persisting it. + * + * @return {@link Rollout} object + */ + Rollout generateRollout(); + + /** + * Generates an empty {@link RolloutGroup} without persisting it. + * + * @return {@link RolloutGroup} object + */ + RolloutGroup generateRolloutGroup(); + + /** + * Generates an empty {@link SoftwareModule} without persisting it. + * + * @return {@link SoftwareModule} object + */ + SoftwareModule generateSoftwareModule(); + + /** + * Generates a {@link SoftwareModule} without persisting it. + * + * @param type + * of the {@link SoftwareModule} + * @param name + * abstract name of the {@link SoftwareModule} + * @param version + * of the {@link SoftwareModule} + * @param description + * of the {@link SoftwareModule} + * @param vendor + * of the {@link SoftwareModule} + * + * @return {@link SoftwareModule} object + */ + SoftwareModule generateSoftwareModule(SoftwareModuleType type, String name, String version, String description, + String vendor); + + /** + * Generates an empty {@link SoftwareModuleMetadata} pair without persisting + * it. + * + * @return {@link SoftwareModuleMetadata} object + */ + SoftwareModuleMetadata generateSoftwareModuleMetadata(); + + /** + * Generates a {@link SoftwareModuleMetadata} pair without persisting it. + * + * @param softwareModule + * {@link SoftwareModuleMetadata#getSoftwareModule()} + * @param key + * {@link SoftwareModuleMetadata#getKey()} + * @param value + * {@link SoftwareModuleMetadata#getValue()} + * + * @return {@link SoftwareModuleMetadata} object + */ + SoftwareModuleMetadata generateSoftwareModuleMetadata(SoftwareModule softwareModule, String key, String value); + + /** + * Generates an empty {@link SoftwareModuleType} without persisting it. + * + * @return {@link SoftwareModuleType} object + */ + SoftwareModuleType generateSoftwareModuleType(); + + /** + * Generates a {@link SoftwareModuleType} without persisting it. + * + * @param key + * {@link SoftwareModuleType#getKey()} + * @param name + * {@link SoftwareModuleType#getName()} + * @param description + * {@link SoftwareModuleType#getDescription()} + * @param maxAssignments + * {@link SoftwareModuleType#getMaxAssignments()} + * + * @return {@link SoftwareModuleType} object + */ + SoftwareModuleType generateSoftwareModuleType(String key, String name, String description, int maxAssignments); + + /** + * Generates an empty {@link Target} without persisting it. + * {@link Target#getSecurityToken()} is generated. + * + * @param controllerID + * of the {@link Target} + * + * @return {@link Target} object + */ + Target generateTarget(@NotEmpty String controllerID); + + /** + * Generates an empty {@link Target} without persisting it. + * + * @param controllerID + * of the {@link Target} + * @param securityToken + * of the {@link Target} for authentication if enabled on tenant. + * Generates one if empty or null. + * + * @return {@link Target} object + */ + Target generateTarget(@NotEmpty String controllerID, @NotEmpty String securityToken); + + /** + * Generates an empty {@link TargetFilterQuery} without persisting it. + * + * @return {@link TargetFilterQuery} object + */ + TargetFilterQuery generateTargetFilterQuery(); + + /** + * Generates an empty {@link TargetTag} without persisting it. + * + * @return {@link TargetTag} object + */ + TargetTag generateTargetTag(); + + /** + * Generates a {@link TargetTag} without persisting it. + * + * @param name + * of the tag + * @return {@link TargetTag} object + */ + TargetTag generateTargetTag(String name); + + /** + * Generates a {@link TargetTag} without persisting it. + * + * @param name + * of the tag + * @param description + * of the tag + * @param colour + * of the tag + * @return {@link TargetTag} object + */ + TargetTag generateTargetTag(String name, String description, String colour); + + /** + * Generates an empty {@link LocalArtifact} without persisting it. + * + * @return {@link LocalArtifact} object + */ + LocalArtifact generateLocalArtifact(); + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/OffsetBasedPageRequest.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/OffsetBasedPageRequest.java similarity index 70% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/OffsetBasedPageRequest.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/OffsetBasedPageRequest.java index 753ec6963..bf7807db0 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/OffsetBasedPageRequest.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/OffsetBasedPageRequest.java @@ -14,13 +14,9 @@ import org.springframework.data.domain.Sort; /** * An implementation of the {@link PageRequest} which is offset based by means * the offset is given and not the page number as in the original - * {@link PageRequest} implemntation where the offset is generated. Due that the - * REST-API is working with {@code offset} and {@code limit} parameter we need - * an offset based page request for JPA. - * - * @author Michael Hirsch - * @since 0.2.2 - * + * {@link PageRequest} implementation where the offset is generated. Due that + * the REST-API is working with {@code offset} and {@code limit} parameter we + * need an offset based page request. */ public final class OffsetBasedPageRequest extends PageRequest { @@ -66,4 +62,31 @@ public final class OffsetBasedPageRequest extends PageRequest { return "OffsetBasedPageRequest [offset=" + offset + ", getPageSize()=" + getPageSize() + ", getPageNumber()=" + getPageNumber() + "]"; } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + offset; + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (!(obj instanceof OffsetBasedPageRequest)) { + return false; + } + final OffsetBasedPageRequest other = (OffsetBasedPageRequest) obj; + if (offset != other.offset) { + return false; + } + return true; + } + } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java new file mode 100644 index 000000000..a27154868 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java @@ -0,0 +1,211 @@ +/** + * 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; + +import java.io.Serializable; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.repository.report.model.DataReportSeries; +import org.eclipse.hawkbit.repository.report.model.InnerOuterDataReportSeries; +import org.eclipse.hawkbit.repository.report.model.ListReportSeries; +import org.eclipse.hawkbit.repository.report.model.SeriesTime; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Service layer for generating hawkBit statistics and reports. + * + */ +public interface ReportManagement { + + /** + * Data base format. + * + * + * + * @param + */ + public interface DateType { + /** + * @param s + * @return T + */ + T format(String s); + + /** + * h2 format. + * + * @return String + */ + String h2Format(); + + /** + * mysql format. + * + * @return String + */ + String mySqlFormat(); + } + + /** + * Return DateTypes. + */ + public static final class DateTypes implements Serializable { + private static final long serialVersionUID = 1L; + private static final PerMonth PER_MONTH = new PerMonth(); + + private DateTypes() { + // Utility class + } + + /** + * @return PerMonth + */ + public static PerMonth perMonth() { + return PER_MONTH; + } + + } + + /** + * Gives the date format based on DB H2 or mySql. + * + * + * + */ + public static final class PerMonth implements DateType, Serializable { + private static final long serialVersionUID = 1L; + private static final String DATE_PATTERN = "yyyy-MM"; + + @Override + public LocalDate format(final String s) { + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_PATTERN); + final YearMonth ym = YearMonth.parse(s, formatter); + return ym.atDay(1); + } + + @Override + public String h2Format() { + return DATE_PATTERN; + } + + @Override + public String mySqlFormat() { + return "%Y-%m"; + } + + } + + /** + * Generates a report of the top x distribution set assigned usage as a list + * of {@link InnerOuterDataReportSeries} which is ideal for generate a donut + * chart out of it. The inner series contains the distribution set names and + * total count usage. The outer series contains each version usage and its + * usage count. {@code inner: ds1:5 -> outer: vers 0.0.0:3, vers 1.0.0:2} + * {@code inner: ds2:1 -> outer: vers 0.0.1:1} + * + * The top x entries are seperated within the series, the rest of the + * distribution sets usage are summarized to a "misc" series. + * + * @param topXEntries + * the top entries which should be shown, the rest distribution + * set entries are summarized as "misc" + * @return a list of inner and outer series of distribution set usage + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List> distributionUsageAssigned(int topXEntries); + + /** + * Generates a report of the top x distribution set installed usage as a + * list of {@link InnerOuterDataReportSeries} which is ideal for generate a + * donut chart out of it. The inner series contains the distribution set + * names and total count usage. The outer series contains each version usage + * and its usage count. + * {@code inner: ds1:5 -> outer: vers 0.0.0:3, vers 1.0.0:2} + * {@code inner: ds2:1 -> outer: vers 0.0.1:1} + * + * The top x entries are seperated within the series, the rest of the + * distribution sets usage are summarized to a "misc" series. + * + * @param topXEntries + * the top entries which should be shown, the rest distribution + * set entries are summarized as "misc" + * @return a list of inner and outer series of distribution set usage + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List> distributionUsageInstalled(int topXEntries); + + /** + * Generates report for feedback over period. + * + * @param dateType + * {@link PerMonth} + * @param from + * start date + * @param to + * end date + * @return DataReportSeries ListReportSeries list of action status + * count + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DataReportSeries feedbackReceivedOverTime(@NotNull DateType dateType, + @NotNull LocalDateTime from, @NotNull LocalDateTime to); + + /** + * Generates report for target created over period. + * + * @param dateType + * {@link PerMonth} + * @param from + * start date + * @param to + * end date + * @return DataReportSeries ListReportSeries list of target created + * count + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DataReportSeries targetsCreatedOverPeriod(@NotNull DateType dateType, + @NotNull LocalDateTime from, @NotNull LocalDateTime to); + + /** + * Generates a report as a {@link ListReportSeries} targets polled based on + * the {@link TargetInfo#getLastTargetQuery()} within an hour, day, week, + * month, year, more than a year, never. + * + * The order of the numbers within the {@link DataReportSeries} is the order + * hour, day, week, month, year, more than a year, never. + * + * @return a {@link DataReportSeries} which contains the number of targets + * which have not been polled in the last hour, day, ... year,more + * than a year, never. + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DataReportSeries targetsLastPoll(); + + /** + * Generates a report of all targets of their current update status count. + * For each {@link TargetUpdateStatus} an total count of targets which are + * in this status currently. + * + * @return a data report series which contains the target count for each + * target update status + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DataReportSeries targetStatus(); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RepositoryConstants.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RepositoryConstants.java new file mode 100644 index 000000000..f2cd3f9f6 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RepositoryConstants.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository; + +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.DistributionSetType; + +/** + * Repository constants. + * + */ +public final class RepositoryConstants { + + /** + * Prefix that the server puts in front of + * {@link ActionStatus#getMessages()} if the message is generated by the + * server. + */ + public static final String SERVER_MESSAGE_PREFIX = "Update Server: "; + + /** + * Number of {@link DistributionSetType}s that are generated as part of + * default tenant setup. + */ + public static final int DEFAULT_DS_TYPES_IN_TENANT = 2; + + private RepositoryConstants() { + // Utility class. + } + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RepositoryProperties.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RepositoryProperties.java new file mode 100644 index 000000000..c60089fb3 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RepositoryProperties.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository; + +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for the repository. + * + */ +@ConfigurationProperties("hawkbit.server.repository") +public class RepositoryProperties { + + /** + * Set to true if the repository has to reject + * {@link ActionStatus} entries for actions that are closed. Note: if this + * is enforced you have to make sure that the feedback channel from the + * devices i in order. + */ + private boolean rejectActionStatusForClosedAction = false; + + public boolean isRejectActionStatusForClosedAction() { + return rejectActionStatusForClosedAction; + } + + public void setRejectActionStatusForClosedAction(final boolean rejectActionStatusForClosedAction) { + this.rejectActionStatusForClosedAction = rejectActionStatusForClosedAction; + } + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java new file mode 100644 index 000000000..512b9af3c --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java @@ -0,0 +1,153 @@ +/** + * 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; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetWithActionStatus; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Repository management service for RolloutGroup. + * + */ +public interface RolloutGroupManagement { + + /** + * Retrieves a page of {@link RolloutGroup}s filtered by a given + * {@link Rollout} with the detailed status. + * + * @param rolloutId + * the ID of the rollout to filter the {@link RolloutGroup}s + * @param pageable + * the page request to sort and limit the result + * @return a page of found {@link RolloutGroup}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Page findAllRolloutGroupsWithDetailedStatus(@NotNull Long rolloutId, @NotNull Pageable pageable); + + /** + * + * Find all targets with action status by rollout group id. The action + * status might be {@code null} if for the target within the rollout no + * actions as been created, e.g. the target already had assigned the same + * distribution set we do not create an action for it but the target is in + * the result list of the rollout-group. + * + * @param pageRequest + * the page request to sort and limit the result + * @param rolloutGroup + * rollout group + * @return {@link TargetWithActionStatus} target with action status + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ) + Page findAllTargetsWithActionStatus(@NotNull PageRequest pageRequest, + @NotNull RolloutGroup rolloutGroup); + + /** + * Retrieves a single {@link RolloutGroup} by its ID. + * + * @param rolloutGroupId + * the ID of the rollout group to find + * @return the found {@link RolloutGroup} by its ID or {@code null} if it + * does not exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + RolloutGroup findRolloutGroupById(@NotNull Long rolloutGroupId); + + /** + * Retrieves a page of {@link RolloutGroup}s filtered by a given + * {@link Rollout} and the an rsql filter. + * + * @param rollout + * the rollout to filter the {@link RolloutGroup}s + * @param rsqlParam + * the specification to filter the result set based on attributes + * of the {@link RolloutGroup} + * @param pageable + * the page request to sort and limit the result + * @return a page of found {@link RolloutGroup}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Page findRolloutGroupsAll(@NotNull Rollout rollout, @NotNull String rsqlParam, + @NotNull Pageable pageable); + + /** + * Retrieves a page of {@link RolloutGroup}s filtered by a given + * {@link Rollout}. + * + * @param rolloutId + * the ID of the rollout to filter the {@link RolloutGroup}s + * @param pageable + * the page request to sort and limit the result + * @return a page of found {@link RolloutGroup}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Page findRolloutGroupsByRolloutId(@NotNull Long rolloutId, @NotNull Pageable pageable); + + /** + * Get targets of specified rollout group. + * + * @param rolloutGroup + * rollout group + * @param page + * the page request to sort and limit the result + * + * @return Page list of targets of a rollout group + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ) + Page findRolloutGroupTargets(@NotNull RolloutGroup rolloutGroup, @NotNull Pageable page); + + /** + * Get targets of specified rollout group. + * + * @param rolloutGroup + * rollout group + * @param rsqlParam + * the specification for filtering the targets of a rollout group + * @param pageable + * the page request to sort and limit the result + * + * @return Page list of targets of a rollout group + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ) + Page findRolloutGroupTargets(@NotNull RolloutGroup rolloutGroup, @NotNull String rsqlParam, + @NotNull Pageable pageable); + + /** + * Get count of targets in different status in rollout group. + * + * @param rolloutGroupId + * rollout group id + * @return rolloutGroup with details of targets count for different statuses + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + RolloutGroup findRolloutGroupWithDetailedStatus(@NotNull Long rolloutGroupId); +} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java new file mode 100644 index 000000000..337475318 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java @@ -0,0 +1,339 @@ +/** + * 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; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupCreatedEvent; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * RolloutManagement to control rollouts e.g. like creating, starting, resuming + * and pausing rollouts. This service secures all the functionality based on the + * {@link PreAuthorize} annotation on methods. + */ +public interface 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() {
+     *     public Void call() throws Exception {
+     *        //run system-code
+     *     }
+     * });
+     *  }
+     * 
+ * + * 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 + * less than (lastcheck-delay). + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) + void checkRunningRollouts(long delayBetweenChecks); + + /** + * Counts all {@link Rollout}s in the repository. + * + * @return number of roll outs + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Long countRolloutsAll(); + + /** + * Count rollouts by given text in name or description. + * + * @param searchText + * name or description + * @return total count rollouts for specified filter text. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Long countRolloutsAllByFilters(@NotEmpty String searchText); + + /** + * Persists a new rollout entity. The filter within the + * {@link Rollout#getTargetFilterQuery()} is used to retrieve the targets + * 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 + * the amount of groups to split the rollout into + * @param conditions + * 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. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) + Rollout createRollout(@NotNull Rollout rollout, int amountGroup, @NotNull RolloutGroupConditions conditions); + + /** + * Persists a new rollout entity. The filter within the + * {@link Rollout#getTargetFilterQuery()} is used to retrieve the targets + * which are effected by this rollout to create. The creation of the rollout + * 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 + * the number of groups should be created for the rollout and + * split up the targets + * @param conditions + * the rolloutgroup conditions and actions which should be + * applied for each {@link RolloutGroup} + * @return the created rollout entity in state + * {@link RolloutStatus#CREATING} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) + Rollout createRolloutAsync(@NotNull Rollout rollout, int amountGroup, @NotNull RolloutGroupConditions conditions); + + /** + * Retrieves all rollouts. + * + * @param pageable + * the page request to sort and limit the result + * @return a page of found rollouts + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Page findAll(@NotNull Pageable pageable); + + /** + * Get count of targets in different status in rollout. + * + * @param pageable + * the page request to sort and limit the result + * @return a list of rollouts with details of targets count for different + * statuses + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Page findAllRolloutsWithDetailedStatus(@NotNull Pageable pageable); + + /** + * Retrieves all rollouts found by the given specification. + * + * @param rsqlParam + * the specification to filter rollouts + * @param pageable + * the page request to sort and limit the result + * @return a page of found rollouts + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Page findAllWithDetailedStatusByPredicate(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * Finds rollouts by given text in name or description. + * + * @param pageable + * the page request to sort and limit the result + * @param searchText + * search text which matches name or description of rollout + * @return the founded rollout or {@code null} if rollout with given ID does + * not exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Slice findRolloutByFilters(@NotNull Pageable pageable, @NotEmpty String searchText); + + /** + * 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 + * not exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Rollout findRolloutById(@NotNull Long rolloutId); + + /** + * 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 + * does not exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Rollout findRolloutByName(@NotNull String rolloutName); + + /** + * Get count of targets in different status in rollout. + * + * @param rolloutId + * rollout id + * @return rollout details of targets count for different statuses + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Rollout findRolloutWithDetailedStatus(@NotNull Long rolloutId); + + /*** + * Get finished percentage details for a specified group which is in running + * state. + * + * @param rolloutId + * the ID of the {@link Rollout} + * @param rolloutGroup + * the ID of the {@link RolloutGroup} + * @return percentage finished + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + float getFinishedPercentForRunningGroup(@NotNull Long rolloutId, @NotNull RolloutGroup rolloutGroup); + + /** + * Pauses a rollout which is currently running. The Rollout switches + * {@link RolloutStatus#PAUSED}. {@link RolloutGroup}s which are currently + * running will be untouched. {@link RolloutGroup}s which are + * {@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. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) + void pauseRollout(@NotNull Rollout rollout); + + /** + * 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. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) + void resumeRollout(@NotNull Rollout rollout); + + /** + * Starts a rollout which has been created. The rollout must be in + * {@link RolloutStatus#READY} state. The according actions will be created + * 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. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) + Rollout startRollout(@NotNull Rollout rollout); + + /** + * Starts a rollout asynchronously which has been created. The rollout must + * be in {@link RolloutStatus#READY} state. The according actions will be + * created asynchronously 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 the started rollout + * + * @throws RolloutIllegalStateException + * if given rollout is not in {@link RolloutStatus#READY}. Only + * ready rollouts can be started. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) + Rollout startRolloutAsync(@NotNull Rollout rollout); + + /** + * Update rollout details. + * + * @param rollout + * rollout to be updated + * + * @return Rollout updated rollout + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) + Rollout updateRollout(@NotNull Rollout rollout); + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutProperties.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutProperties.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutProperties.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutProperties.java index 2384fa480..9b3a37093 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutProperties.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutProperties.java @@ -18,12 +18,6 @@ import org.springframework.stereotype.Component; @Component @ConfigurationProperties("hawkbit.rollout") public class RolloutProperties { - private final Scheduler scheduler = new Scheduler(); - - public Scheduler getScheduler() { - return scheduler; - } - /** * Rollout scheduler configuration. */ @@ -47,4 +41,10 @@ public class RolloutProperties { } + private final Scheduler scheduler = new Scheduler(); + + public Scheduler getScheduler() { + return scheduler; + } + } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java new file mode 100644 index 000000000..0934e871e --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java @@ -0,0 +1,486 @@ +/** + * 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; + +import java.util.Collection; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Service for managing {@link SoftwareModule}s. + * + */ +public interface SoftwareManagement { + + /** + * Counts {@link SoftwareModule}s with given + * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} + * and {@link SoftwareModule#getType()} that are not marked as deleted. + * + * @param searchText + * to search for in name and version + * @param type + * to filter the result + * @return number of found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModuleByFilters(String searchText, SoftwareModuleType type); + + /** + * Count all {@link SoftwareModule}s in the repository that are not marked + * as deleted. + * + * @return number of {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModulesAll(); + + /** + * Counts {@link SoftwareModule}s with given {@link SoftwareModuleType}. + * + * @param type + * to count + * @return number of found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModulesByType(@NotNull SoftwareModuleType type); + + /** + * @return number of {@link SoftwareModuleType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModuleTypesAll(); + + /** + * Create {@link SoftwareModule}s in the repository. + * + * @param swModules + * {@link SoftwareModule}s to create + * @return SoftwareModule + * @throws EntityAlreadyExistsException + * if a given entity already exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createSoftwareModule(@NotNull Collection swModules); + + /** + * + * @param swModule + * SoftwareModule to create + * @return SoftwareModule + * @throws EntityAlreadyExistsException + * if a given entity already exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + SoftwareModule createSoftwareModule(@NotNull SoftwareModule swModule); + + /** + * creates a list of software module meta data entries. + * + * @param metadata + * the meta data entries to create or update + * @return the updated or created software module meta data entries + * @throws EntityAlreadyExistsException + * in case one of the meta data entry already exists for the + * specific key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List createSoftwareModuleMetadata(@NotNull Collection metadata); + + /** + * creates or updates a single software module meta data entry. + * + * @param metadata + * the meta data entry to create or update + * @return the updated or created software module meta data entry + * @throws EntityAlreadyExistsException + * in case the meta data entry already exists for the specific + * key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModuleMetadata createSoftwareModuleMetadata(@NotNull SoftwareModuleMetadata metadata); + + /** + * Creates multiple {@link SoftwareModuleType}s. + * + * @param types + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createSoftwareModuleType(@NotNull final Collection types); + + /** + * Creates new {@link SoftwareModuleType}. + * + * @param type + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + SoftwareModuleType createSoftwareModuleType(@NotNull SoftwareModuleType type); + + /** + * Deletes the given {@link SoftwareModule} {@link Entity}. + * + * @param bsm + * is the {@link SoftwareModule} to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteSoftwareModule(@NotNull SoftwareModule bsm); + + /** + * deletes a software module meta data entry. + * + * @param id + * the ID of the software module meta data to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + void deleteSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotNull String key); + + /** + * Deletes {@link SoftwareModule}s which is any if the given ids. + * + * @param ids + * of the Software Modules to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteSoftwareModules(@NotNull Collection ids); + + /** + * Deletes or marks as delete in case the type is in use. + * + * @param type + * to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteSoftwareModuleType(@NotNull SoftwareModuleType type); + + /** + * @param pageable + * the page request to page the result set + * @param set + * to search for + * @return all {@link SoftwareModule}s that are assigned to given + * {@link DistributionSet}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleByAssignedTo(@NotNull Pageable pageable, @NotNull DistributionSet set); + + /** + * @param pageable + * the page request to page the result set + * @param set + * to search for + * @param type + * to filter + * @return all {@link SoftwareModule}s that are assigned to given + * {@link DistributionSet} filtered by {@link SoftwareModuleType}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleByAssignedToAndType(@NotNull Pageable pageable, @NotNull DistributionSet set, + @NotNull SoftwareModuleType type); + + /** + * Filter {@link SoftwareModule}s with given + * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} + * and {@link SoftwareModule#getType()} that are not marked as deleted. + * + * @param pageable + * page parameter + * @param searchText + * to be filtered as "like" on {@link SoftwareModule#getName()} + * @param type + * to be filtered as "like" on {@link SoftwareModule#getType()} + * @return the page of found {@link SoftwareModule} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModuleByFilters(@NotNull Pageable pageable, String searchText, + SoftwareModuleType type); + + /** + * Finds {@link SoftwareModule} by given id. + * + * @param id + * to search for + * @return the found {@link SoftwareModule}s or null if not + * found. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_CONTROLLER) + SoftwareModule findSoftwareModuleById(@NotNull Long id); + + /** + * retrieves {@link SoftwareModule} by their name AND version AND type.. + * + * @param name + * of the {@link SoftwareModule} + * @param version + * of the {@link SoftwareModule} + * @param type + * of the {@link SoftwareModule} + * @return the found {@link SoftwareModule} or null + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModule findSoftwareModuleByNameAndVersion(@NotEmpty String name, @NotEmpty String version, + @NotNull SoftwareModuleType type); + + /** + * finds a single software module meta data by its id. + * + * @param id + * the id of the software module meta data containing the meta + * data key and the ID of the software module + * @return the found SoftwareModuleMetadata or {@code null} if not exits + * @throws EntityNotFoundException + * in case the meta data does not exists for the given key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleMetadata findSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotEmpty String key); + + /** + * finds all meta data by the given software module id. + * + * @param swId + * the software module id to retrieve the meta data from + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given software + * module id + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleMetadataBySoftwareModuleId(@NotNull Long swId, + @NotNull Pageable pageable); + + /** + * finds all meta data by the given software module id. + * + * @param softwareModuleId + * the software module id to retrieve the meta data from + * @param spec + * the specification to filter the result + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given software + * module id + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleMetadataBySoftwareModuleId(@NotNull Long softwareModuleId, + @NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * Filter {@link SoftwareModule}s with given + * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} + * search text and {@link SoftwareModule#getType()} that are not marked as + * deleted and sort them by means of given distribution set related modules + * on top of the list. + * + * After that the modules are sorted by {@link SoftwareModule#getName()} and + * {@link SoftwareModule#getVersion()} in ascending order. + * + * @param pageable + * page parameter + * @param orderByDistributionId + * the ID of distribution set to be ordered on top + * @param searchText + * filtered as "like" on {@link SoftwareModule#getName()} + * @param type + * filtered as "equal" on {@link SoftwareModule#getType()} + * @return the page of found {@link SoftwareModule} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc( + @NotNull Pageable pageable, @NotNull Long orderByDistributionId, String searchText, + SoftwareModuleType type); + + /** + * Retrieves all software modules. Deleted ones are filtered. + * + * @param pageable + * pagination parameter + * @return the found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModulesAll(@NotNull Pageable pageable); + + /** + * Retrieves all software modules with a given list of ids + * {@link SoftwareModule#getId()}. + * + * @param ids + * to search for + * @return {@link List} of found {@link SoftwareModule}s + */ + List findSoftwareModulesById(@NotEmpty Collection ids); + + /** + * Retrieves all {@link SoftwareModule}s with a given specification. + * + * @param spec + * the specification to filter the software modules + * @param pageable + * pagination parameter + * @return the found {@link SoftwareModule}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModulesByPredicate(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * retrieves the {@link SoftwareModule}s by their {@link SoftwareModuleType} + * . + * + * @param pageable + * page parameters + * @param type + * to be filtered on + * @return the found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModulesByType(@NotNull Pageable pageable, @NotNull SoftwareModuleType type); + + /** + * + * @param id + * to search for + * @return {@link SoftwareModuleType} in the repository with given + * {@link SoftwareModuleType#getId()} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleType findSoftwareModuleTypeById(@NotNull Long id); + + /** + * + * @param key + * to search for + * @return {@link SoftwareModuleType} in the repository with given + * {@link SoftwareModuleType#getKey()} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleType findSoftwareModuleTypeByKey(@NotNull String key); + + /** + * + * @param name + * to search for + * @return all {@link SoftwareModuleType}s in the repository with given + * {@link SoftwareModuleType#getName()} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleType findSoftwareModuleTypeByName(@NotNull String name); + + /** + * @param pageable + * parameter + * @return all {@link SoftwareModuleType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleTypesAll(@NotNull Pageable pageable); + + /** + * Retrieves all {@link SoftwareModuleType}s with a given specification. + * + * @param spec + * the specification to filter the software modules types + * @param pageable + * pagination parameter + * @return the found {@link SoftwareModuleType}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleTypesAll(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * Retrieves software module including details ( + * {@link SoftwareModule#getArtifacts()}). + * + * @param id + * parameter + * @param isDeleted + * parameter + * @return the found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModule findSoftwareModuleWithDetails(@NotNull Long id); + + /** + * Updates existing {@link SoftwareModule}. Update-able values are + * {@link SoftwareModule#getDescription()} + * {@link SoftwareModule#getVendor()}. + * + * @param sm + * to update + * + * @return the saved {@link Entity}. + * + * @throws NullPointerException + * of {@link SoftwareModule#getId()} is null + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModule updateSoftwareModule(@NotNull SoftwareModule sm); + + /** + * updates a distribution set meta data value if corresponding entry exists. + * + * @param metadata + * the meta data entry to be updated + * @return the updated meta data entry + * @throws EntityNotFoundException + * in case the meta data entry does not exists and cannot be + * updated + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModuleMetadata updateSoftwareModuleMetadata(@NotNull SoftwareModuleMetadata metadata); + + /** + * Updates existing {@link SoftwareModuleType}. Update-able value is + * {@link SoftwareModuleType#getDescription()} and + * {@link SoftwareModuleType#getColour()}. + * + * @param sm + * to update + * @return updated {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModuleType updateSoftwareModuleType(@NotNull SoftwareModuleType sm); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java new file mode 100644 index 000000000..a44b13d92 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java @@ -0,0 +1,91 @@ +/** + * 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; + +import java.util.List; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.TenantMetaData; +import org.eclipse.hawkbit.repository.report.model.SystemUsageReport; +import org.eclipse.hawkbit.tenancy.TenantAware; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Central system management operations of the update server. + * + */ +public interface SystemManagement { + + /** + * Checks if a specific tenant exists. The tenant will not be created lazy. + * + * @return {@code true} in case the tenant exits or {@code false} if not + */ + String currentTenant(); + + /** + * Deletes all data related to a given tenant. + * + * @param tenant + * to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN) + void deleteTenant(@NotNull String tenant); + + /** + * + * @return list of all tenant names in the system. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN) + List findTenants(); + + /** + * Calculated system usage statistics, both overall for the entire system + * and per tenant; + * + * @return SystemUsageReport of the current system + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN) + SystemUsageReport getSystemUsageStatistics(); + + /** + * @return {@link TenantMetaData} of {@link TenantAware#getCurrentTenant()} + */ + TenantMetaData getTenantMetadata(); + + /** + * Returns {@link TenantMetaData} of given and current tenant. Creates for + * new tenants also two {@link SoftwareModuleType} (os and app) and + * {@link RepositoryConstants#DEFAULT_DS_TYPES_IN_TENANT} + * {@link DistributionSetType}s (os and os_app). + * + * DISCLAIMER: this variant is used during initial login (where the tenant + * is not yet in the session). Please user {@link #getTenantMetadata()} for + * regular requests. + * + * @param tenant + * to retrieve data for + * @return {@link TenantMetaData} of given tenant + */ + TenantMetaData getTenantMetadata(@NotNull String tenant); + + /** + * Update call for {@link TenantMetaData}. + * + * @param metaData + * to update + * @return updated {@link TenantMetaData} entity + */ + TenantMetaData updateTenantMetadata(@NotNull TenantMetaData metaData); + +} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TagManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TagManagement.java new file mode 100644 index 000000000..1b80444b5 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TagManagement.java @@ -0,0 +1,248 @@ +/** + * 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; + +import java.util.Collection; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.Tag; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetTag; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Management service for {@link Tag}s. + * + */ +public interface TagManagement { + + /** + * count {@link TargetTag}s. + * + * @return size of {@link TargetTag}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + long countTargetTags(); + + /** + * Creates a {@link DistributionSet}. + * + * @param distributionSetTag + * to be created. + * @return the new {@link DistributionSet} + * @throws EntityAlreadyExistsException + * if distributionSetTag already exists + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + DistributionSetTag createDistributionSetTag(@NotNull DistributionSetTag distributionSetTag); + + /** + * Creates multiple {@link DistributionSetTag}s. + * + * @param distributionSetTags + * to be created + * @return the new {@link DistributionSetTag} + * @throws EntityAlreadyExistsException + * if a given entity already exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createDistributionSetTags(@NotNull Collection distributionSetTags); + + /** + * Creates a new {@link TargetTag}. + * + * @param targetTag + * to be created + * + * @return the new created {@link TargetTag} + * + * @throws EntityAlreadyExistsException + * if given object already exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) + TargetTag createTargetTag(@NotNull TargetTag targetTag); + + /** + * created multiple {@link TargetTag}s. + * + * @param targetTags + * to be created + * @return the new created {@link TargetTag}s + * + * @throws EntityAlreadyExistsException + * if given object has already an ID. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) + List createTargetTags(@NotNull Collection targetTags); + + /** + * Deletes {@link DistributionSetTag} by given + * {@link DistributionSetTag#getName()}. + * + * @param tagName + * to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteDistributionSetTag(@NotEmpty String tagName); + + /** + * Deletes {@link TargetTag} with given name. + * + * @param targetTagName + * tag name of the {@link TargetTag} to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET) + void deleteTargetTag(@NotEmpty String targetTagName); + + /** + * + * @return all {@link DistributionSetTag}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List findAllDistributionSetTags(); + + /** + * returns all {@link DistributionSetTag}s. + * + * @param pageReq + * page parameter + * @return all {@link DistributionSetTag}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findAllDistributionSetTags(@NotNull Pageable pageReq); + + /** + * Retrieves all DistributionSet tags based on the given specification. + * + * @param rsqlParam + * rsql query string + * @param pageable + * pagination parameter + * @return the found {@link DistributionSetTag}s, never {@code null} + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findAllDistributionSetTags(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * @return all {@link TargetTag}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findAllTargetTags(); + + /** + * returns all {@link TargetTag}s. + * + * @param pageable + * page parameter + * + * @return all {@link TargetTag}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Page findAllTargetTags(@NotNull Pageable pageable); + + /** + * Retrieves all target tags based on the given specification. + * + * @param rsqlParam + * rsql query string + * @param pageable + * pagination parameter + * @return the found {@link Target}s, never {@code null} + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Page findAllTargetTags(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * Find {@link DistributionSet} based on given name. + * + * @param name + * to look for. + * @return {@link DistributionSet} or null if it does not exist + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetTag findDistributionSetTag(@NotEmpty String name); + + /** + * Finds {@link DistributionSetTag} by given id. + * + * @param id + * to search for + * @return the found {@link DistributionSetTag}s or null if not + * found. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetTag findDistributionSetTagById(@NotNull Long id); + + /** + * Find {@link TargetTag} based on given Name. + * + * @param name + * to look for. + * @return {@link TargetTag} or null if it does not exist + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + TargetTag findTargetTag(@NotEmpty String name); + + /** + * Finds {@link TargetTag} by given id. + * + * @param id + * to search for + * @return the found {@link TargetTag}s or null if not found. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + TargetTag findTargetTagById(@NotNull Long id); + + /** + * Updates an existing {@link DistributionSetTag}. + * + * @param distributionSetTag + * to be updated + * @return the updated {@link DistributionSet} + * @throws NullPointerException + * of {@link DistributionSetTag#getName()} is null + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetTag updateDistributionSetTag(@NotNull DistributionSetTag distributionSetTag); + + /** + * updates the {@link TargetTag}. + * + * @param targetTag + * the {@link TargetTag} with updated values + * @return the updated {@link TargetTag} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + TargetTag updateTargetTag(@NotNull TargetTag targetTag); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java new file mode 100644 index 000000000..d748ed470 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java @@ -0,0 +1,117 @@ +/** + * 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; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.model.TargetFilterQuery; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Management service for {@link TargetFilterQuery}s. + * + */ +public interface TargetFilterQueryManagement { + + /** + * creating new {@link TargetFilterQuery}. + * + * @param customTargetFilter + * @return the created {@link TargetFilterQuery} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) + TargetFilterQuery createTargetFilterQuery(@NotNull TargetFilterQuery customTargetFilter); + + /** + * Delete target filter query. + * + * @param targetFilterQueryId + * IDs of target filter query to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET) + void deleteTargetFilterQuery(@NotNull Long targetFilterQueryId); + + /** + * Verifies provided filter syntax. + * + * @param query + * to verify + * + * @return true if syntax is valid + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + boolean verifyTargetFilterQuerySyntax(String query); + + /** + * + * Retrieves all target filter query{@link TargetFilterQuery}. + * + * @param pageable + * pagination parameter + * @return the found {@link TargetFilterQuery}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Page findAllTargetFilterQuery(@NotNull Pageable pageable); + + /** + * Retrieves all target filter query which {@link TargetFilterQuery}. + * + * + * @param pageable + * pagination parameter + * @param name + * target filter query name + * @return the page with the found {@link TargetFilterQuery} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Page findTargetFilterQueryByFilters(@NotNull Pageable pageable, String name); + + /** + * Find target filter query by id. + * + * @param targetFilterQueryId + * Target filter query id + * @return the found {@link TargetFilterQuery} + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + TargetFilterQuery findTargetFilterQueryById(@NotNull Long targetFilterQueryId); + + /** + * Find target filter query by name. + * + * @param targetFilterQueryName + * Target filter query name + * @return the found {@link TargetFilterQuery} + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + TargetFilterQuery findTargetFilterQueryByName(@NotNull String targetFilterQueryName); + + /** + * updates the {@link TargetFilterQuery}. + * + * @param targetFilterQuery + * to be updated + * @return the updated {@link TargetFilterQuery} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + TargetFilterQuery updateTargetFilterQuery(@NotNull TargetFilterQuery targetFilterQuery); +} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java new file mode 100644 index 000000000..5fdfb318e --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java @@ -0,0 +1,598 @@ +/** + * 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; + +import java.net.URI; +import java.util.Collection; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Tag; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetFilterQuery; +import org.eclipse.hawkbit.repository.model.TargetIdName; +import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.hawkbit.repository.model.TargetTag; +import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Management service for {@link Target}s. + * + */ +public interface TargetManagement { + + /** + * Assign a {@link TargetTag} assignment to given {@link Target}s. + * + * @param targetIds + * to assign for + * @param tag + * to assign + * @return list of assigned targets + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + List assignTag(@NotEmpty Collection targetIds, @NotNull TargetTag tag); + + /** + * Counts number of targets with given + * {@link Target#getAssignedDistributionSet()}. + * + * @param distId + * to search for + * + * @return number of found {@link Target}s. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Long countTargetByAssignedDistributionSet(@NotNull Long distId); + + /** + * Count {@link Target}s for all the given filter parameters. + * + * @param status + * find targets having on of these {@link TargetUpdateStatus}s. + * Set to null in case this is not required. + * @param searchText + * to find targets having the text anywhere in name or + * description. Set null in case this is not + * required. + * @param installedOrAssignedDistributionSetId + * to find targets having the {@link DistributionSet} as + * installed or assigned. Set to null in case this + * is not required. + * @param tagNames + * to find targets which are having any one in this tag names. + * Set null in case this is not required. + * @param selectTargetWithNoTag + * flag to select targets with no tag assigned + * + * @return the found number {@link Target}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Long countTargetByFilters(Collection status, String searchText, + Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, String... tagNames); + + /** + * Counts number of targets with given + * {@link TargetInfo#getInstalledDistributionSet()}. + * + * @param distId + * to search for + * @return number of found {@link Target}s. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Long countTargetByInstalledDistributionSet(@NotNull Long distId); + + /** + * Count {@link TargetFilterQuery}s for given target filter query. + * + * @param targetFilterQuery + * {link TargetFilterQuery} + * @return the found number {@link TargetFilterQuery}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Long countTargetByTargetFilterQuery(@NotEmpty String targetFilterQuery); + + /** + * Count {@link TargetFilterQuery}s for given filter parameter. + * + * @param targetFilterQuery + * {link TargetFilterQuery} + * @return the found number {@link TargetFilterQuery}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Long countTargetByTargetFilterQuery(@NotNull TargetFilterQuery targetFilterQuery); + + /** + * Counts all {@link Target}s in the repository. + * + * @return number of targets + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Long countTargetsAll(); + + /** + * creating a new {@link Target}. + * + * @param target + * to be created + * @return the created {@link Target} + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_CONTROLLER) + Target createTarget(@NotNull Target target); + + /** + * creating new {@link Target}s including poll status data. useful + * especially in plug and play scenarios. + * + * @param target + * to be created * + * @param status + * of the target + * @param lastTargetQuery + * if a plug and play case + * @param address + * if a plug and play case + * + * @throws EntityAlreadyExistsException + * if {@link Target} with given {@link Target#getControllerId()} + * already exists. + * + * @return created {@link Target} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_CONTROLLER) + Target createTarget(@NotNull Target target, @NotNull TargetUpdateStatus status, Long lastTargetQuery, URI address); + + /** + * creates multiple {@link Target}s. If some of the given {@link Target}s + * already exists in the DB a {@link EntityAlreadyExistsException} is + * thrown. {@link Target}s contain all objects of the parameter targets, + * including duplicates. + * + * @param targets + * to be created. + * @return the created {@link Target}s + * + * @throws EntityAlreadyExistsException + * of one of the given targets already exist. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) + List createTargets(@NotNull Collection targets); + + /** + * Deletes all targets with the given IDs. + * + * @param targetIDs + * the technical IDs of the targets to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET) + void deleteTargets(@NotEmpty Long... targetIDs); + + /** + * finds all {@link Target#getControllerId()} which are currently in the + * database. + * + * @return all IDs of all {@link Target} in the system + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findAllTargetIds(); + + /** + * Finds all targets for all the given parameters but returns not the full + * target but {@link TargetIdName}. + * + * @param pageRequest + * the pageRequest to enhance the query for paging and sorting + * + * @param filterByStatus + * find targets having this {@link TargetUpdateStatus}s. Set to + * null in case this is not required. + * @param filterBySearchText + * to find targets having the text anywhere in name or + * description. Set null in case this is not + * required. + * @param installedOrAssignedDistributionSetId + * to find targets having the {@link DistributionSet} as + * installed or assigned. Set to null in case this + * is not required. + * @param filterByTagNames + * to find targets which are having any one in this tag names. + * Set null in case this is not required. + * @param selectTargetWithNoTag + * flag to select targets with no tag assigned + * + * @return the found {@link TargetIdName}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findAllTargetIdsByFilters(@NotNull Pageable pageRequest, + Collection filterByStatus, String filterBySearchText, + Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, String... filterByTagNames); + + /** + * Finds all targets for all the given parameter {@link TargetFilterQuery} + * and returns not the full target but {@link TargetIdName}. + * + * @param pageRequest + * the pageRequest to enhance the query for paging and sorting + * @param targetFilterQuery + * {@link TargetFilterQuery} + * @return the found {@link TargetIdName}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findAllTargetIdsByTargetFilterQuery(@NotNull Pageable pageRequest, + @NotNull TargetFilterQuery targetFilterQuery); + + /** + * retrieves {@link Target}s by the assigned {@link DistributionSet} without + * details, i.e. NO {@link Target#getTags()} and {@link Target#getActions()} + * possible. + * + * + * @param distributionSetID + * the ID of the {@link DistributionSet} + * @param pageReq + * page parameter + * @return the found {@link Target}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET) + Page findTargetByAssignedDistributionSet(@NotNull Long distributionSetID, @NotNull Pageable pageReq); + + /** + * Retrieves {@link Target}s by the assigned {@link DistributionSet} without + * details, i.e. NO {@link Target#getTags()} and {@link Target#getActions()} + * possible including additional filtering based on the given {@code spec}. + * + * @param distributionSetID + * the ID of the {@link DistributionSet} + * @param rsqlParam + * the specification to filter the result set + * @param pageReq + * page parameter + * @return the found {@link Target}s, never {@code null} + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET) + Page findTargetByAssignedDistributionSet(@NotNull Long distributionSetID, @NotNull String rsqlParam, + @NotNull Pageable pageReq); + + /** + * Find {@link Target} based on given ID returns found Target without + * details, i.e. NO {@link Target#getTags()} and {@link Target#getActions()} + * possible. + * + * @param controllerIDs + * to look for. + * @return List of found{@link Target}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findTargetByControllerID(@NotEmpty Collection controllerIDs); + + /** + * Find {@link Target} based on given ID returns found Target without + * details, i.e. NO {@link Target#getTags()} and {@link Target#getActions()} + * possible. + * + * @param controllerId + * to look for. + * @return {@link Target} or null if it does not exist + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Target findTargetByControllerID(@NotEmpty String controllerId); + + /** + * Find {@link Target} based on given ID returns found Target with details, + * i.e. {@link Target#getTags()} and {@link Target#getActions()} are + * possible. + * + * Note: try to use {@link #findTargetByControllerID(String)} as much as + * possible. + * + * @param controllerId + * to look for. + * @return {@link Target} or null if it does not exist + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Target findTargetByControllerIDWithDetails(@NotEmpty String controllerId); + + /** + * Filter {@link Target}s for all the given parameters. If all parameters + * except pageable are null, all available {@link Target}s are returned. + * + * @param pageable + * page parameters + * @param status + * find targets having this {@link TargetUpdateStatus}s. Set to + * null in case this is not required. + * @param searchText + * to find targets having the text anywhere in name or + * description. Set null in case this is not + * required. + * @param installedOrAssignedDistributionSetId + * to find targets having the {@link DistributionSet} as + * installed or assigned. Set to null in case this + * is not required. + * @param tagNames + * to find targets which are having any one in this tag names. + * Set null in case this is not required. + * @param selectTargetWithNoTag + * flag to select targets with no tag assigned + * + * @return the found {@link Target}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Slice findTargetByFilters(@NotNull Pageable pageable, Collection status, + String searchText, Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, + String... tagNames); + + /** + * retrieves {@link Target}s by the installed {@link DistributionSet}without + * details, i.e. NO {@link Target#getTags()} and {@link Target#getActions()} + * possible. + * + * @param distributionSetID + * the ID of the {@link DistributionSet} + * @param pageReq + * page parameter + * @return the found {@link Target}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET) + Page findTargetByInstalledDistributionSet(@NotNull Long distributionSetID, @NotNull Pageable pageReq); + + /** + * retrieves {@link Target}s by the installed {@link DistributionSet}without + * details, i.e. NO {@link Target#getTags()} and {@link Target#getActions()} + * possible including additional filtering based on the given {@code spec}. + * + * @param distributionSetId + * the ID of the {@link DistributionSet} + * @param rsqlParam + * the specification to filter the result + * @param pageable + * page parameter + * @return the found {@link Target}s, never {@code null} + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET) + Page findTargetByInstalledDistributionSet(@NotNull Long distributionSetId, @NotNull String rsqlParam, + @NotNull Pageable pageable); + + /** + * Retrieves the {@link Target} which have a certain + * {@link TargetUpdateStatus} without details, i.e. NO + * {@link Target#getTags()} and {@link Target#getActions()} possible. + * + * @param pageable + * page parameter + * @param status + * the {@link TargetUpdateStatus} to be filtered on + * @return the found {@link Target}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Page findTargetByUpdateStatus(@NotNull Pageable pageable, @NotNull TargetUpdateStatus status); + + /** + * Retrieves all targets without details, i.e. NO {@link Target#getTags()} + * and {@link Target#getActions()} possible + * + * @param pageable + * pagination parameter + * @return the found {@link Target}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Slice findTargetsAll(@NotNull Pageable pageable); + + /** + * Retrieves all targets without details, i.e. NO {@link Target#getTags()} + * and {@link Target#getActions()} possible based on + * {@link TargetFilterQuery#getQuery()} + * + * @param targetFilterQuery + * in string notation + * @param pageable + * pagination parameter + * + * @return the found {@link Target}s, never {@code null} + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Page findTargetsAll(@NotNull String targetFilterQuery, @NotNull Pageable pageable); + + /** + * Retrieves all targets without details, i.e. NO {@link Target#getTags()} + * and {@link Target#getActions()} possible based on + * {@link TargetFilterQuery#getQuery()} + * + * @param targetFilterQuery + * the specification for the query + * @param pageable + * pagination parameter + * + * @return the found {@link Target}s, never {@code null} + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Slice findTargetsAll(@NotNull TargetFilterQuery targetFilterQuery, @NotNull Pageable pageable); + + /** + * method retrieves all {@link Target}s from the repo in the following + * order: + *

+ * 1) {@link Target}s which have the given {@link DistributionSet} as + * {@link Target#getTargetInfo()} + * {@link TargetInfo#getInstalledDistributionSet()} + *

+ * 2) {@link Target}s which have the given {@link DistributionSet} as + * {@link Target#getAssignedDistributionSet()} + *

+ * 3) {@link Target}s which have no connection to the given + * {@link DistributionSet}. + * + * @param pageable + * the page request to page the result set + * @param orderByDistributionId + * {@link DistributionSet#getId()} to be ordered by + * @param filterByDistributionId + * {@link DistributionSet#getId()} to be filter the result. Set + * to null in case this is not required. + * @param filterByStatus + * find targets having this {@link TargetUpdateStatus}s. Set to + * null in case this is not required. + * @param filterBySearchText + * to find targets having the text anywhere in name or + * description. Set null in case this is not + * required. + * @param installedOrAssignedDistributionSetId + * to find targets having the {@link DistributionSet} as + * installed or assigned. Set to null in case this + * is not required. + * @param filterByTagNames + * to find targets which are having any one in this tag names. + * Set null in case this is not required. + * @param selectTargetWithNoTag + * flag to select targets with no tag assigned + * @return a paged result {@link Page} of the {@link Target}s in a defined + * order. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Slice findTargetsAllOrderByLinkedDistributionSet(@NotNull Pageable pageable, + @NotNull Long orderByDistributionId, Long filterByDistributionId, + Collection filterByStatus, String filterBySearchText, Boolean selectTargetWithNoTag, + String... filterByTagNames); + + /** + * retrieves a list of {@link Target}s by their controller ID with details, + * i.e. {@link Target#getTags()} are possible. + * + * Note: try to use {@link #findTargetByControllerID(String)} as much as + * possible. + * + * @param controllerIDs + * {@link Target}s Names parameter + * @return the found {@link Target}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findTargetsByControllerIDsWithTags(@NotNull List controllerIDs); + + /** + * Find targets by tag name. + * + * @param tagName + * tag name + * @return list of matching targets + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + List findTargetsByTag(@NotEmpty String tagName); + + /** + * Toggles {@link TargetTag} assignment to given {@link Target}s by means + * that if some (or all) of the targets in the list have the {@link Tag} not + * yet assigned, they will be. If all of theme have the tag already assigned + * they will be removed instead. + * + * @param targetIds + * to toggle for + * @param tagName + * to toggle + * @return TagAssigmentResult with all meta data of the assignment outcome. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + TargetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection targetIds, @NotEmpty String tagName); + + /** + * {@link Target} based method call for + * {@link #toggleTagAssignment(Collection, String)}. + * + * @param targets + * to toggle for + * @param tag + * to toggle + * @return TagAssigmentResult with all meta data of the assignment outcome. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + TargetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection targets, @NotNull TargetTag tag); + + /** + * Un-assign all {@link Target} from a given {@link TargetTag} . + * + * @param tag + * to un-assign all targets + * @return list of unassigned targets + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + List unAssignAllTargetsByTag(@NotNull TargetTag tag); + + /** + * Un-assign a {@link TargetTag} assignment to given {@link Target}. + * + * @param controllerID + * to un-assign for + * @param targetTag + * to un-assign + * @return the unassigned target or if no target is unassigned + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + Target unAssignTag(@NotEmpty String controllerID, @NotNull TargetTag targetTag); + + /** + * updates the {@link Target}. + * + * @param target + * to be updated + * @return the updated {@link Target} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_CONTROLLER) + Target updateTarget(@NotNull Target target); + + /** + * updates multiple {@link Target}s. + * + * @param targets + * to be updated + * @return the updated {@link Target}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_CONTROLLER) + List updateTargets(@NotNull Collection targets); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java new file mode 100644 index 000000000..9c467f9dd --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java @@ -0,0 +1,141 @@ +/** + * 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; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.model.TenantConfiguration; +import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidatorException; +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.env.Environment; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Management service for tenant configurations. + * + */ +public interface TenantConfigurationManagement { + + /** + * Adds or updates a specific configuration for a specific tenant. + * + * + * @param configurationKey + * the key of the configuration + * @param value + * the configuration value which will be written into the + * database. + * @return the configuration value which was just written into the database. + * @throws TenantConfigurationValidatorException + * if the {@code propertyType} and the value in general does not + * match the expected type and format defined by the Key + * @throws ConversionFailedException + * if the property cannot be converted to the given + */ + @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) + TenantConfigurationValue addOrUpdateConfiguration(TenantConfigurationKey configurationKey, T value); + + /** + * Build the tenant configuration by the given key + * + * @param configurationKey + * the key + * @param propertyType + * the property type + * @param tenantConfiguration + * the configuration + * @return if no default value is set and no database value available + * or returns the tenant configuration value + */ + @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) + TenantConfigurationValue buildTenantConfigurationValueByKey(TenantConfigurationKey configurationKey, + Class propertyType, TenantConfiguration tenantConfiguration); + + /** + * Deletes a specific configuration for the current tenant. Does nothing in + * case there is no tenant specific configuration value. + * + * @param configurationKey + * the configuration key to be deleted + */ + @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) + void deleteConfiguration(TenantConfigurationKey configurationKey); + + /** + * Retrieves a configuration value from the e.g. tenant overwritten + * configuration values or in case the tenant does not a have a specific + * configuration the global default value hold in the {@link Environment}. + * + * @param configurationKey + * the key of the configuration + * @return the converted configuration value either from the tenant specific + * configuration stored or from the fall back default values or + * {@code null} in case key has not been configured and not default + * value exists + * @throws TenantConfigurationValidatorException + * if the {@code propertyType} and the value in general does not + * match the expected type and format defined by the Key + * @throws ConversionFailedException + * if the property cannot be converted to the given + * {@code propertyType} + */ + @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) + TenantConfigurationValue getConfigurationValue(TenantConfigurationKey configurationKey); + + /** + * Retrieves a configuration value from the e.g. tenant overwritten + * configuration values or in case the tenant does not a have a specific + * configuration the global default value hold in the {@link Environment}. + * + * @param + * the type of the configuration value + * @param configurationKey + * the key of the configuration + * @param propertyType + * the type of the configuration value, e.g. {@code String.class} + * , {@code Integer.class}, etc + * @return the converted configuration value either from the tenant specific + * configuration stored or from the fallback default values or + * {@code null} in case key has not been configured and not default + * value exists + * @throws TenantConfigurationValidatorException + * if the {@code propertyType} and the value in general does not + * match the expected type and format defined by the Key + * @throws ConversionFailedException + * if the property cannot be converted to the given + * {@code propertyType} + */ + @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) + TenantConfigurationValue getConfigurationValue(TenantConfigurationKey configurationKey, + Class propertyType); + + /** + * returns the global configuration property either defined in the property + * file or an default value otherwise. + * + * @param + * the type of the configuration value + * @param configurationKey + * the key of the configuration + * @param propertyType + * the type of the configuration value, e.g. {@code String.class} + * , {@code Integer.class}, etc + * @return the global configured value + * @throws TenantConfigurationValidatorException + * if the {@code propertyType} and the value in the property + * file or the default value does not match the expected type + * and format defined by the Key + * @throws ConversionFailedException + * if the property cannot be converted to the given + * {@code propertyType} + */ + @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) + T getGlobalConfigurationValue(TenantConfigurationKey configurationKey, Class propertyType); +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantStatsManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantStatsManagement.java new file mode 100644 index 000000000..f041bc45f --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantStatsManagement.java @@ -0,0 +1,33 @@ +/** + * 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; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.report.model.TenantUsage; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Management service for statistics of a single tenant. + * + */ +@FunctionalInterface +public interface TenantStatsManagement { + + /** + * Service for stats of the current tenant. + * + * @return collected statistics + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_SYSTEM_CODE) + TenantUsage getStatsOfTenant(); + +} \ No newline at end of file diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/AbstractBaseEntityEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/AbstractBaseEntityEvent.java similarity index 88% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/AbstractBaseEntityEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/AbstractBaseEntityEvent.java index d27669ade..d13e89ee7 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/AbstractBaseEntityEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/AbstractBaseEntityEvent.java @@ -6,8 +6,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; +import org.eclipse.hawkbit.eventbus.event.AbstractDistributedEvent; +import org.eclipse.hawkbit.eventbus.event.EntityEvent; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/AbstractEntityBulkEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/AbstractEntityBulkEvent.java similarity index 96% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/AbstractEntityBulkEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/AbstractEntityBulkEvent.java index 56f3e585a..f8d43d6cd 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/AbstractEntityBulkEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/AbstractEntityBulkEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import java.util.Arrays; import java.util.List; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/AbstractPropertyChangeEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/AbstractPropertyChangeEvent.java similarity index 97% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/AbstractPropertyChangeEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/AbstractPropertyChangeEvent.java index 795f6ff88..97cf13b66 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/AbstractPropertyChangeEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/AbstractPropertyChangeEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import java.util.Map; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/ActionCreatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/ActionCreatedEvent.java similarity index 93% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/ActionCreatedEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/ActionCreatedEvent.java index 5efdca2a9..73188b85e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/ActionCreatedEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/ActionCreatedEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import org.eclipse.hawkbit.repository.model.Action; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/ActionPropertyChangeEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/ActionPropertyChangeEvent.java similarity index 94% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/ActionPropertyChangeEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/ActionPropertyChangeEvent.java index 822f9bbeb..84487547e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/ActionPropertyChangeEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/ActionPropertyChangeEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import java.util.Map; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagAssigmentResultEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagAssigmentResultEvent.java similarity index 94% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagAssigmentResultEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagAssigmentResultEvent.java index e10b9a51f..d723251da 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagAssigmentResultEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagAssigmentResultEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagCreatedBulkEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagCreatedBulkEvent.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagCreatedBulkEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagCreatedBulkEvent.java index fb7c4a862..2fc08c272 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagCreatedBulkEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagCreatedBulkEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import java.util.List; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagDeletedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagDeletedEvent.java similarity index 93% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagDeletedEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagDeletedEvent.java index b909390d1..f2f134a3a 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagDeletedEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagDeletedEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import org.eclipse.hawkbit.repository.model.DistributionSetTag; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagUpdateEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagUpdateEvent.java similarity index 93% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagUpdateEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagUpdateEvent.java index 2825322f9..d74872b01 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/DistributionSetTagUpdateEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetTagUpdateEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import org.eclipse.hawkbit.repository.model.DistributionSetTag; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DownloadProgressEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DownloadProgressEvent.java new file mode 100644 index 000000000..6d145e0ae --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DownloadProgressEvent.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.eventbus.event; + +import org.eclipse.hawkbit.eventbus.event.AbstractDistributedEvent; + +/** + * Event that contains an updated download progress for a given ActionStatus + * that was written for a download request. + * + */ +public class DownloadProgressEvent extends AbstractDistributedEvent { + + private static final long serialVersionUID = 1L; + + private final Long statusId; + private final long requestedBytes; + private final long shippedBytesSinceLast; + private final long shippedBytesOverall; + + /** + * Constructor. + * + * @param tenant + * the tenant for this event + * @param statusId + * of ActionStatus that was written for the download request + * @param requestedBytes + * bytes requested + * @param shippedBytesSinceLast + * bytes since last event + * @param shippedBytesOverall + * on the download request + */ + public DownloadProgressEvent(final String tenant, final Long statusId, final Long requestedBytes, + final Long shippedBytesSinceLast, final Long shippedBytesOverall) { + // the revision of the DownloadProgressEvent is just equal the + // shippedBytesOverall as this is a growing number. + super(shippedBytesOverall, tenant); + this.statusId = statusId; + this.requestedBytes = requestedBytes; + this.shippedBytesSinceLast = shippedBytesSinceLast; + this.shippedBytesOverall = shippedBytesOverall; + } + + public Long getStatusId() { + return statusId; + } + + public long getRequestedBytes() { + return requestedBytes; + } + + public long getShippedBytesSinceLast() { + return shippedBytesSinceLast; + } + + public long getShippedBytesOverall() { + return shippedBytesOverall; + } +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/EntityBulkEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/EntityBulkEvent.java similarity index 91% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/EntityBulkEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/EntityBulkEvent.java index eac1b6bb9..0102fda47 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/EntityBulkEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/EntityBulkEvent.java @@ -6,11 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import java.io.Serializable; import java.util.List; +import org.eclipse.hawkbit.eventbus.event.Event; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutChangeEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutChangeEvent.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutChangeEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutChangeEvent.java index 8f15602b5..2ff739726 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutChangeEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutChangeEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import org.eclipse.hawkbit.eventbus.event.AbstractEvent; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutGroupChangeEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupChangeEvent.java similarity index 92% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutGroupChangeEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupChangeEvent.java index cbda44ef5..5c36ab61f 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutGroupChangeEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupChangeEvent.java @@ -6,7 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; + +import org.eclipse.hawkbit.eventbus.event.AbstractEvent; /** * Event declaration for the UI to notify the UI that a rollout has been diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutGroupCreatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupCreatedEvent.java similarity index 94% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutGroupCreatedEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupCreatedEvent.java index 465ff6088..41f08c91d 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutGroupCreatedEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupCreatedEvent.java @@ -6,7 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; + +import org.eclipse.hawkbit.eventbus.event.AbstractDistributedEvent; /** * Event definition which is been published in case a rollout group has been diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutGroupPropertyChangeEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupPropertyChangeEvent.java similarity index 94% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutGroupPropertyChangeEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupPropertyChangeEvent.java index 6caa46547..887a1c2ff 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutGroupPropertyChangeEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupPropertyChangeEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import java.util.Map; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutPropertyChangeEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutPropertyChangeEvent.java similarity index 94% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutPropertyChangeEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutPropertyChangeEvent.java index 5f72307df..9287a0fb3 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/RolloutPropertyChangeEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutPropertyChangeEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import java.util.Map; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetAssignDistributionSetEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetAssignDistributionSetEvent.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetAssignDistributionSetEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetAssignDistributionSetEvent.java index 68b3f1289..077e05462 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetAssignDistributionSetEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetAssignDistributionSetEvent.java @@ -6,11 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import java.net.URI; import java.util.Collection; +import org.eclipse.hawkbit.eventbus.event.AbstractEvent; import org.eclipse.hawkbit.repository.model.SoftwareModule; /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetCreatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetCreatedEvent.java similarity index 93% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetCreatedEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetCreatedEvent.java index 7e89565b1..446f21856 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetCreatedEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetCreatedEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import org.eclipse.hawkbit.repository.model.Target; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetInfoUpdateEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetInfoUpdateEvent.java similarity index 93% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetInfoUpdateEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetInfoUpdateEvent.java index 563bb4bdc..1e7e29719 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetInfoUpdateEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetInfoUpdateEvent.java @@ -6,8 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; +import org.eclipse.hawkbit.eventbus.event.EntityEvent; import org.eclipse.hawkbit.repository.model.TargetInfo; /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagAssigmentResultEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagAssigmentResultEvent.java similarity index 94% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagAssigmentResultEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagAssigmentResultEvent.java index 6bdc3aebd..b846a80da 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagAssigmentResultEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagAssigmentResultEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagCreatedBulkEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagCreatedBulkEvent.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagCreatedBulkEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagCreatedBulkEvent.java index c66a5150e..950c351e0 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagCreatedBulkEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagCreatedBulkEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import java.util.List; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagDeletedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagDeletedEvent.java similarity index 93% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagDeletedEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagDeletedEvent.java index 040fbc19a..ebf6c73c9 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagDeletedEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagDeletedEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import org.eclipse.hawkbit.repository.model.TargetTag; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagUpdateEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagUpdateEvent.java similarity index 93% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagUpdateEvent.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagUpdateEvent.java index 4562063aa..f87443235 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetTagUpdateEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetTagUpdateEvent.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.eventbus.event; import org.eclipse.hawkbit.repository.model.TargetTag; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ArtifactDeleteFailedException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ArtifactDeleteFailedException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ArtifactDeleteFailedException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ArtifactDeleteFailedException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ArtifactUploadFailedException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ArtifactUploadFailedException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ArtifactUploadFailedException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ArtifactUploadFailedException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/CancelActionNotAllowedException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/CancelActionNotAllowedException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/CancelActionNotAllowedException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/CancelActionNotAllowedException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ConcurrentModificationException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ConcurrentModificationException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ConcurrentModificationException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ConcurrentModificationException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/DistributionSetCreationFailedMissingMandatoryModuleException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/DistributionSetCreationFailedMissingMandatoryModuleException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/DistributionSetCreationFailedMissingMandatoryModuleException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/DistributionSetCreationFailedMissingMandatoryModuleException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/DistributionSetTypeUndefinedException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/DistributionSetTypeUndefinedException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/DistributionSetTypeUndefinedException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/DistributionSetTypeUndefinedException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/EntityAlreadyExistsException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityAlreadyExistsException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/EntityAlreadyExistsException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityAlreadyExistsException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/EntityLockedException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityLockedException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/EntityLockedException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityLockedException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/EntityReadOnlyException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityReadOnlyException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/EntityReadOnlyException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityReadOnlyException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ForceQuitActionNotAllowedException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ForceQuitActionNotAllowedException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ForceQuitActionNotAllowedException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ForceQuitActionNotAllowedException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/GridFSDBFileNotFoundException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/GridFSDBFileNotFoundException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/GridFSDBFileNotFoundException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/GridFSDBFileNotFoundException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/IncompleteDistributionSetException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/IncompleteDistributionSetException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/IncompleteDistributionSetException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/IncompleteDistributionSetException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/InsufficientPermissionException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/InsufficientPermissionException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/InsufficientPermissionException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/InsufficientPermissionException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/InvalidMD5HashException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/InvalidMD5HashException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/InvalidMD5HashException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/InvalidMD5HashException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/InvalidSHA1HashException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/InvalidSHA1HashException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/InvalidSHA1HashException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/InvalidSHA1HashException.java diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/InvalidTargetAddressException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/InvalidTargetAddressException.java new file mode 100644 index 000000000..70b890483 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/InvalidTargetAddressException.java @@ -0,0 +1,42 @@ +/** + * 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.exception; + +import org.eclipse.hawkbit.exception.SpServerError; +import org.eclipse.hawkbit.exception.SpServerRtException; + +/** + * Exception which is thrown when trying to set an invalid target address. + */ +public class InvalidTargetAddressException extends SpServerRtException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * @param message + * the message for this exception + */ + public InvalidTargetAddressException(final String message) { + super(message, SpServerError.SP_REPO_INVALID_TARGET_ADDRESS); + } + + /** + * + * @param message + * the message for this exception + * @param cause + * the cause for this exception + */ + public InvalidTargetAddressException(final String message, final Throwable cause) { + super(message, SpServerError.SP_REPO_INVALID_TARGET_ADDRESS, cause); + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/MultiPartFileUploadException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/MultiPartFileUploadException.java new file mode 100644 index 000000000..e37786e19 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/MultiPartFileUploadException.java @@ -0,0 +1,30 @@ +/** + * 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.exception; + +import org.eclipse.hawkbit.exception.SpServerError; +import org.eclipse.hawkbit.exception.SpServerRtException; + +/** + * Thrown if a multi part exception occurred. + * + */ +public final class MultiPartFileUploadException extends SpServerRtException { + + private static final long serialVersionUID = 1L; + + /** + * @param cause + * for the exception + */ + public MultiPartFileUploadException(final Throwable cause) { + super(cause.getMessage(), SpServerError.SP_ARTIFACT_UPLOAD_FAILED, cause); + } + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLParameterSyntaxException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/RSQLParameterSyntaxException.java similarity index 97% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLParameterSyntaxException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/RSQLParameterSyntaxException.java index aa43f1bbb..268ab02ba 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLParameterSyntaxException.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/RSQLParameterSyntaxException.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.exception; import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.exception.SpServerRtException; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLParameterUnsupportedFieldException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/RSQLParameterUnsupportedFieldException.java similarity index 97% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLParameterUnsupportedFieldException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/RSQLParameterUnsupportedFieldException.java index e95368acb..df58ecc8b 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLParameterUnsupportedFieldException.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/RSQLParameterUnsupportedFieldException.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.exception; import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.exception.SpServerRtException; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/RolloutIllegalStateException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/RolloutIllegalStateException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/RolloutIllegalStateException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/RolloutIllegalStateException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/TenantNotExistException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/TenantNotExistException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/TenantNotExistException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/TenantNotExistException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ToManyAttributeEntriesException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ToManyAttributeEntriesException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ToManyAttributeEntriesException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ToManyAttributeEntriesException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ToManyStatusEntriesException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ToManyStatusEntriesException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/ToManyStatusEntriesException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ToManyStatusEntriesException.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/UnsupportedSoftwareModuleForThisDistributionSetException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/UnsupportedSoftwareModuleForThisDistributionSetException.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/exception/UnsupportedSoftwareModuleForThisDistributionSetException.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/UnsupportedSoftwareModuleForThisDistributionSetException.java diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Action.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Action.java new file mode 100644 index 000000000..98d101471 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Action.java @@ -0,0 +1,218 @@ +/** + * 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; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * Operations to be executed by the target. Usually a software update. Other + * supported actions are the cancellation of a running update action or a + * refresh request for target attributes. + * + */ +public interface Action extends TenantAwareBaseEntity { + + /** + * @return the distributionSet + */ + DistributionSet getDistributionSet(); + + /** + * @param distributionSet + * the distributionSet to set + */ + void setDistributionSet(DistributionSet distributionSet); + + /** + * @return true when action is in state + * {@link Status#CANCELING} or {@link Status#CANCELED}, false + * otherwise + */ + default boolean isCancelingOrCanceled() { + return Status.CANCELING.equals(getStatus()) || Status.CANCELED.equals(getStatus()); + } + + /** + * @return current {@link Status} of the {@link Action}. + */ + Status getStatus(); + + /** + * @param status + * of the {@link Action} + */ + void setStatus(Status status); + + /** + * @return true if {@link Action} is still running. + */ + boolean isActive(); + + /** + * @return the {@link ActionType} + */ + ActionType getActionType(); + + /** + * @return list of {@link ActionStatus} entries. + */ + List getActionStatus(); + + /** + * @param target + * of this {@link Action} + */ + void setTarget(Target target); + + /** + * @return {@link Target} of this {@link Action}. + */ + Target getTarget(); + + /** + * @return time in {@link TimeUnit#MILLISECONDS} after which + * {@link #isForced()} switches to true in case of + * {@link ActionType#TIMEFORCED}. + */ + long getForcedTime(); + + /** + * @return rolloutGroup related to this {@link Action}. + */ + RolloutGroup getRolloutGroup(); + + /** + * @return rollout related to this {@link Action}. + */ + Rollout getRollout(); + + /** + * checks if the {@link #getForcedTime()} is hit by the given + * {@code hitTimeMillis}, by means if the given milliseconds are greater + * than the forcedTime. + * + * @param hitTimeMillis + * the milliseconds, mostly the + * {@link System#currentTimeMillis()} + * @return {@code true} if this {@link #getActionType()} is in + * {@link ActionType#TIMEFORCED} and the given {@code hitTimeMillis} + * is greater than the {@link #getForcedTime()} otherwise + * {@code false} + */ + default boolean isHitAutoForceTime(final long hitTimeMillis) { + if (ActionType.TIMEFORCED.equals(getActionType())) { + return hitTimeMillis >= getForcedTime(); + } + return false; + } + + /** + * @return {@code true} if either the {@link #getActionType()} is + * {@link ActionType#FORCED} or {@link ActionType#TIMEFORCED} but + * then if the {@link #getForcedTime()} has been exceeded otherwise + * always {@code false} + */ + default boolean isForce() { + switch (getActionType()) { + case FORCED: + return true; + case TIMEFORCED: + return isHitAutoForceTime(System.currentTimeMillis()); + default: + return false; + } + } + + /** + * @return true when action is forced, false otherwise + */ + default boolean isForced() { + return ActionType.FORCED.equals(getActionType()); + } + + /** + * Action status as reported by the controller. + * + * Be aware that JPA is persisting the ordinal number of the enum by means + * the ordered number in the enum. So don't re-order the enums within the + * Status enum declaration! + * + */ + public enum Status { + /** + * Action is finished successfully for this target. + */ + FINISHED, + + /** + * Action has failed for this target. + */ + ERROR, + + /** + * Action is still running but with warnings. + */ + WARNING, + + /** + * Action is still running for this target. + */ + RUNNING, + + /** + * Action has been canceled for this target. + */ + CANCELED, + + /** + * Action is in canceling state and waiting for controller confirmation. + */ + CANCELING, + + /** + * Action has been send to the target. + */ + RETRIEVED, + + /** + * Action requests download by this target which has now started. + */ + DOWNLOAD, + + /** + * Action is in waiting state, e.g. the action is scheduled in a rollout + * but not yet activated. + */ + SCHEDULED; + } + + /** + * The action type for this action relation. + * + */ + public enum ActionType { + /** + * Forced action execution. Target is advised to executed immediately. + */ + FORCED, + + /** + * Soft action execution. Target is advised to execute when it fits. + */ + SOFT, + + /** + * {@link #SOFT} action execution until + * {@link Action#isHitAutoForceTime(long)} is reached, {@link #FORCED} + * after that. + */ + TIMEFORCED; + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ActionStatus.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ActionStatus.java new file mode 100644 index 000000000..e83108fe8 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ActionStatus.java @@ -0,0 +1,84 @@ +/** + * 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; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.eclipse.hawkbit.repository.model.Action.Status; + +/** + * Status information of an {@link Action} which can be provided by the + * {@link Target} or is added by the update server itself. This can be the start + * of the {@link Action} life cycle, the end and update notifications in + * between. + * + */ +public interface ActionStatus extends TenantAwareBaseEntity { + + /** + * @return time in {@link TimeUnit#MILLISECONDS} when the status was + * reported. + */ + Long getOccurredAt(); + + /** + * @param occurredAt + * time in {@link TimeUnit#MILLISECONDS} when the status was + * reported. + */ + void setOccurredAt(Long occurredAt); + + /** + * Adds message including splitting in case it exceeds 512 length. + * + * @param message + * to add + */ + void addMessage(String message); + + /** + * @return current {@link Status#DOWNLOAD} progress if known by the update + * server. + */ + int getDownloadProgressPercent(); + + /** + * @return list of message entries that can be added to the + * {@link ActionStatus}. + */ + List getMessages(); + + /** + * @return {@link Action} this {@link ActionStatus} belongs to. + */ + Action getAction(); + + /** + * @param action + * this {@link ActionStatus} belongs to. + */ + void setAction(Action action); + + /** + * @return the {@link Status} of this {@link ActionStatus}. Caused + * potentially a transition change of the {@link #getAction()} if + * different from the previous {@link ActionStatus#getStatus()}. + */ + Status getStatus(); + + /** + * @param status + * of this {@link ActionStatus}. May cause a transition change of + * the {@link #getAction()} if different from the previous + * {@link ActionStatus#getStatus()}. + */ + void setStatus(Status status); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ActionWithStatusCount.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ActionWithStatusCount.java new file mode 100644 index 000000000..268c37853 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ActionWithStatusCount.java @@ -0,0 +1,48 @@ +/** + * 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; + +/** + * View for querying {@link Action} include the count of the action's + * {@link ActionStatus} entries. + * + */ +public interface ActionWithStatusCount { + + /** + * @return {@link Action} + */ + Action getAction(); + + /** + * @return {@link DistributionSet} ID. + */ + Long getDsId(); + + /** + * @return {@link DistributionSet} name. + */ + String getDsName(); + + /** + * @return {@link DistributionSet} version. + */ + String getDsVersion(); + + /** + * @return number of {@link ActionStatus} entries + */ + Long getActionStatusCount(); + + /** + * @return name of the {@link Rollout}. + */ + String getRolloutName(); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Artifact.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Artifact.java new file mode 100644 index 000000000..cc726839d --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Artifact.java @@ -0,0 +1,42 @@ +/** + * 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; + +import com.google.common.io.BaseEncoding; + +/** + * Binaries for a {@link SoftwareModule} Note: the decision which artifacts have + * to be downloaded are done on the device side. e.g. Full Package, Signatures, + * binary deltas + * + */ +public interface Artifact extends TenantAwareBaseEntity { + + /** + * @return {@link SoftwareModule} this {@link Artifact} belongs to. + */ + SoftwareModule getSoftwareModule(); + + /** + * @return MD5 hash of the artifact. + */ + String getMd5Hash(); + + /** + * @return SHA-1 hash of the artifact in {@link BaseEncoding#base16()} + * format. + */ + String getSha1Hash(); + + /** + * @return size of the artifact in bytes. + */ + Long getSize(); + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/CustomSoftwareModule.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/AssignedSoftwareModule.java similarity index 79% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/CustomSoftwareModule.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/AssignedSoftwareModule.java index 34aa8345a..b23b3f0fe 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/CustomSoftwareModule.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/AssignedSoftwareModule.java @@ -14,7 +14,7 @@ import java.io.Serializable; * Use to display software modules for the selected distribution. * */ -public class CustomSoftwareModule implements Serializable { +public class AssignedSoftwareModule implements Serializable { private static final long serialVersionUID = 6144585781451168439L; @@ -31,22 +31,28 @@ public class CustomSoftwareModule implements Serializable { * as true if the software module is assigned and false if not * assigned. */ - public CustomSoftwareModule(final SoftwareModule softwareModule, final boolean assigned) { + public AssignedSoftwareModule(final SoftwareModule softwareModule, final boolean assigned) { this.softwareModule = softwareModule; this.assigned = assigned; } + /** + * @return {@link SoftwareModule} + */ public SoftwareModule getSoftwareModule() { return softwareModule; } + /** + * @return true if assigned + */ public boolean isAssigned() { return assigned; } @Override public String toString() { - return "CustomSoftwareModule [softwareModule=" + softwareModule + ", assigned=" + assigned + "]"; + return "AssignedSoftwareModule [softwareModule=" + softwareModule + ", assigned=" + assigned + "]"; } @Override @@ -66,10 +72,10 @@ public class CustomSoftwareModule implements Serializable { if (obj == null) { return false; } - if (!(obj instanceof CustomSoftwareModule)) { + if (!(obj instanceof AssignedSoftwareModule)) { return false; } - final CustomSoftwareModule other = (CustomSoftwareModule) obj; + final AssignedSoftwareModule other = (AssignedSoftwareModule) obj; if (assigned != other.assigned) { return false; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/AssignmentResult.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/AssignmentResult.java similarity index 80% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/AssignmentResult.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/AssignmentResult.java index 2dea94f33..9468c8a88 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/AssignmentResult.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/AssignmentResult.java @@ -12,6 +12,9 @@ import java.util.List; /** * Generic assignment result bean. + * + * @param + * type of the assigned and unassigned {@link BaseEntity}s. * */ public class AssignmentResult { @@ -19,7 +22,6 @@ public class AssignmentResult { private final int total; private final int assigned; private final int alreadyAssigned; - private final int unassigned; private final List assignedEntity; private final List unassignedEntity; @@ -47,28 +49,45 @@ public class AssignmentResult { this.assignedEntity = assignedEntity; this.unassignedEntity = unassignedEntity; } - + + /** + * @return number of newly assigned elements. + */ public int getAssigned() { return assigned; } - + + /** + * @return total number (assigned and already assigned). + */ public int getTotal() { return total; } - + + /** + * @return number of already assigned/ignored elements. + */ public int getAlreadyAssigned() { return alreadyAssigned; } - + /** + * @return number of unsassigned elements + */ public int getUnassigned() { return unassigned; } + /** + * @return {@link List} of assigned entity. + */ public List getAssignedEntity() { return assignedEntity; } - + + /** + * @return {@link List} of unassigned entity. + */ public List getUnassignedEntity() { return unassignedEntity; } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/BaseEntity.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/BaseEntity.java new file mode 100644 index 000000000..2a9948bc5 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/BaseEntity.java @@ -0,0 +1,49 @@ +/** + * 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; + +import java.io.Serializable; +import java.util.concurrent.TimeUnit; + +import org.springframework.hateoas.Identifiable; + +/** + * Core information of all entities. + * + */ +public interface BaseEntity extends Serializable, Identifiable { + + /** + * @return time in {@link TimeUnit#MILLISECONDS} when the {@link BaseEntity} + * was created. + */ + Long getCreatedAt(); + + /** + * @return user that created the {@link BaseEntity}. + */ + String getCreatedBy(); + + /** + * @return time in {@link TimeUnit#MILLISECONDS} when the {@link BaseEntity} + * was last time changed. + */ + Long getLastModifiedAt(); + + /** + * @return user that updated the {@link BaseEntity} last. + */ + String getLastModifiedBy(); + + /** + * @return version of the {@link BaseEntity}. + */ + long getOptLockRevision(); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSet.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSet.java new file mode 100644 index 000000000..5747b38f3 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSet.java @@ -0,0 +1,132 @@ +/** + * 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; + +import java.util.List; +import java.util.Set; + +import org.eclipse.hawkbit.repository.DistributionSetManagement; + +/** + * A {@link DistributionSet} defines a meta package that combines a set of + * {@link SoftwareModule}s which have to be or are provisioned to a + * {@link Target}. + * + *

+ * A {@link Target} has exactly one target {@link DistributionSet} assigned. + *

+ * + */ +public interface DistributionSet extends NamedVersionedEntity { + + /** + * @return {@link Set} of assigned {@link DistributionSetTag}s. + */ + Set getTags(); + + /** + * @return true if the set is deleted and only kept for history + * purposes. + */ + boolean isDeleted(); + + /** + * @return immutable {@link List} of {@link DistributionSetMetadata} + * elements. See {@link DistributionSetManagement} to alter. + */ + List getMetadata(); + + /** + * @return true if {@link DistributionSet} contains a mandatory + * migration step, i.e. unfinished {@link Action}s will kept active + * and not automatically canceled if overridden by a newer update. + */ + boolean isRequiredMigrationStep(); + + /** + * @param deleted + * to true if {@link DistributionSet} is no longer + * be usage but kept for history purposes. + * @return updated {@link DistributionSet} + */ + DistributionSet setDeleted(boolean deleted); + + /** + * @param isRequiredMigrationStep + * to true if {@link DistributionSet} contains a + * mandatory migration step, i.e. unfinished {@link Action}s will + * kept active and not automatically canceled if overridden by a + * newer update. + * + * @return updated {@link DistributionSet} + */ + DistributionSet setRequiredMigrationStep(boolean isRequiredMigrationStep); + + /** + * @return the assignedTargets + */ + List getAssignedTargets(); + + /** + * @return the installedTargets + */ + List getInstalledTargets(); + + /** + * + * @return unmodifiableSet of {@link SoftwareModule}. + */ + Set getModules(); + + /** + * @param softwareModule + * @return true if the module was added and false + * if it already existed in the set + * + */ + boolean addModule(SoftwareModule softwareModule); + + /** + * Removed given {@link SoftwareModule} from this DS instance. + * + * @param softwareModule + * to remove + * @return true if element was found and removed + */ + boolean removeModule(SoftwareModule softwareModule); + + /** + * Searches through modules for the given type. + * + * @param type + * to search for + * @return SoftwareModule of given type or null if not in the + * list. + */ + SoftwareModule findFirstModuleByType(SoftwareModuleType type); + + /** + * @return type of the {@link DistributionSet}. + */ + DistributionSetType getType(); + + /** + * @param type + * of the {@link DistributionSet}. + */ + void setType(DistributionSetType type); + + /** + * @return true if all defined + * {@link DistributionSetType#getMandatoryModuleTypes()} of + * {@link #getType()} are present in this {@link DistributionSet}. + */ + boolean isComplete(); + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetFilter.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetFilter.java similarity index 97% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetFilter.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetFilter.java index a545209e4..c095d0f7e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetFilter.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetFilter.java @@ -6,45 +6,14 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.model; import java.util.Collection; -import org.eclipse.hawkbit.repository.model.DistributionSetType; - /** * Holds distribution set filter parameters. - * - * - * */ public final class DistributionSetFilter { - private final Boolean isDeleted; - private final Boolean isComplete; - private final DistributionSetType type; - private final String searchText; - private final Boolean selectDSWithNoTag; - private final Collection tagNames; - private final String assignedTargetId; - private final String installedTargetId; - - /** - * Parametric constructor. - * - * @param builder - * DistributionSetFilterBuilder - */ - public DistributionSetFilter(final DistributionSetFilterBuilder builder) { - this.isDeleted = builder.isDeleted; - this.isComplete = builder.isComplete; - this.type = builder.type; - this.searchText = builder.searchText; - this.selectDSWithNoTag = builder.selectDSWithNoTag; - this.tagNames = builder.tagNames; - this.assignedTargetId = builder.assignedTargetId; - this.installedTargetId = builder.installedTargetId; - } - /** * * Distribution set filter builder. @@ -71,8 +40,13 @@ public final class DistributionSetFilter { return new DistributionSetFilter(this); } - public DistributionSetFilterBuilder setIsDeleted(final Boolean isDeleted) { - this.isDeleted = isDeleted; + public DistributionSetFilterBuilder setAssignedTargetId(final String assignedTargetId) { + this.assignedTargetId = assignedTargetId; + return this; + } + + public DistributionSetFilterBuilder setInstalledTargetId(final String installedTargetId) { + this.installedTargetId = installedTargetId; return this; } @@ -81,8 +55,8 @@ public final class DistributionSetFilter { return this; } - public DistributionSetFilterBuilder setType(final DistributionSetType type) { - this.type = type; + public DistributionSetFilterBuilder setIsDeleted(final Boolean isDeleted) { + this.isDeleted = isDeleted; return this; } @@ -101,28 +75,53 @@ public final class DistributionSetFilter { return this; } - public DistributionSetFilterBuilder setAssignedTargetId(final String assignedTargetId) { - this.assignedTargetId = assignedTargetId; - return this; - } - - public DistributionSetFilterBuilder setInstalledTargetId(final String installedTargetId) { - this.installedTargetId = installedTargetId; + public DistributionSetFilterBuilder setType(final DistributionSetType type) { + this.type = type; return this; } } + private final Boolean isDeleted; + private final Boolean isComplete; + private final DistributionSetType type; + private final String searchText; + private final Boolean selectDSWithNoTag; + private final Collection tagNames; + private final String assignedTargetId; - public Boolean getIsDeleted() { - return isDeleted; + private final String installedTargetId; + + /** + * Parametric constructor. + * + * @param builder + * DistributionSetFilterBuilder + */ + public DistributionSetFilter(final DistributionSetFilterBuilder builder) { + this.isDeleted = builder.isDeleted; + this.isComplete = builder.isComplete; + this.type = builder.type; + this.searchText = builder.searchText; + this.selectDSWithNoTag = builder.selectDSWithNoTag; + this.tagNames = builder.tagNames; + this.assignedTargetId = builder.assignedTargetId; + this.installedTargetId = builder.installedTargetId; + } + + public String getAssignedTargetId() { + return assignedTargetId; + } + + public String getInstalledTargetId() { + return installedTargetId; } public Boolean getIsComplete() { return isComplete; } - public DistributionSetType getType() { - return type; + public Boolean getIsDeleted() { + return isDeleted; } public String getSearchText() { @@ -137,12 +136,8 @@ public final class DistributionSetFilter { return tagNames; } - public String getAssignedTargetId() { - return assignedTargetId; - } - - public String getInstalledTargetId() { - return installedTargetId; + public DistributionSetType getType() { + return type; } } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetMetadata.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetMetadata.java new file mode 100644 index 000000000..87a62e9ba --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetMetadata.java @@ -0,0 +1,22 @@ +/** + * 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; + +/** + * {@link MetaData} of a {@link DistributionSet}. + * + */ +public interface DistributionSetMetadata extends MetaData { + + /** + * @return {@link DistributionSet} of this {@link MetaData} entry. + */ + DistributionSet getDistributionSet(); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTag.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTag.java new file mode 100644 index 000000000..05089d138 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTag.java @@ -0,0 +1,25 @@ +/** + * 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; + +import java.util.List; + +/** + * {@link Tag} of a {@link DistributionSet}. + * + */ +public interface DistributionSetTag extends Tag { + + /** + * @return {@link List} of {@link DistributionSet}s this {@link Tag} is + * assigned to. + */ + List getAssignedToDistributionSet(); + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTagAssignmentResult.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTagAssignmentResult.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTagAssignmentResult.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTagAssignmentResult.java diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetType.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetType.java new file mode 100644 index 000000000..cf5da40b2 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetType.java @@ -0,0 +1,173 @@ +/** + * 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; + +import java.util.Set; + +/** + * A {@link DistributionSetType} is an abstract definition for + * {@link DistributionSet} that defines what {@link SoftwareModule}s can be + * added (optional) to {@link DistributionSet} of that type or have to added + * (mandatory) in order to be considered complete. Only complete DS can be + * assigned to a {@link Target}. + * + */ +public interface DistributionSetType extends NamedEntity { + + /** + * @return true if the type is deleted and only kept for + * history purposes. + */ + boolean isDeleted(); + + /** + * @return set of {@link SoftwareModuleType}s that need to be in a + * {@link DistributionSet} of this type to be + * {@link DistributionSet#isComplete()}. + */ + Set getMandatoryModuleTypes(); + + /** + * @return set of optional {@link SoftwareModuleType}s that can be in a + * {@link DistributionSet} of this type. + */ + Set getOptionalModuleTypes(); + + /** + * Checks if the given {@link SoftwareModuleType} is in this + * {@link DistributionSetType}. + * + * @param softwareModuleType + * search for + * @return true if found + */ + default boolean containsModuleType(final SoftwareModuleType softwareModuleType) { + return containsMandatoryModuleType(softwareModuleType) || containsOptionalModuleType(softwareModuleType); + } + + /** + * Checks if the given {@link SoftwareModuleType} is in + * {@link #getMandatoryModuleTypes()}. + * + * @param softwareModuleType + * search for + * @return true if found + */ + default boolean containsMandatoryModuleType(final SoftwareModuleType softwareModuleType) { + return containsMandatoryModuleType(softwareModuleType.getId()); + } + + /** + * Checks if the given {@link SoftwareModuleType} is in + * {@link #getMandatoryModuleTypes()}. + * + * @param softwareModuleTypeId + * search for by {@link SoftwareModuleType#getId()} + * @return true if found + */ + default boolean containsMandatoryModuleType(final Long softwareModuleTypeId) { + return getMandatoryModuleTypes().stream().filter(element -> element.getId().equals(softwareModuleTypeId)) + .findFirst().isPresent(); + } + + /** + * Checks if the given {@link SoftwareModuleType} is in + * {@link #getOptionalModuleTypes()}. + * + * @param softwareModuleType + * search for + * @return true if found + */ + default boolean containsOptionalModuleType(final SoftwareModuleType softwareModuleType) { + return containsOptionalModuleType(softwareModuleType.getId()); + } + + /** + * Checks if the given {@link SoftwareModuleType} is in + * {@link #getOptionalModuleTypes()}. + * + * @param softwareModuleTypeId + * search by {@link SoftwareModuleType#getId()} + * @return true if found + */ + default boolean containsOptionalModuleType(final Long softwareModuleTypeId) { + return getOptionalModuleTypes().stream().filter(element -> element.getId().equals(softwareModuleTypeId)) + .findFirst().isPresent(); + } + + /** + * Compares the modules of this {@link DistributionSetType} and the given + * one. + * + * @param dsType + * to compare with + * @return true if the lists are identical. + */ + boolean areModuleEntriesIdentical(DistributionSetType dsType); + + /** + * Adds {@link SoftwareModuleType} that is optional for the + * {@link DistributionSet}. + * + * @param smType + * to add + * @return updated instance + */ + DistributionSetType addOptionalModuleType(SoftwareModuleType smType); + + /** + * Adds {@link SoftwareModuleType} that is mandatory for the + * {@link DistributionSet}. + * + * @param smType + * to add + * @return updated instance + */ + DistributionSetType addMandatoryModuleType(SoftwareModuleType smType); + + /** + * Removes {@link SoftwareModuleType} from the list. + * + * @param smTypeId + * to remove + * @return updated instance + */ + DistributionSetType removeModuleType(Long smTypeId); + + /** + * @return business key of this {@link DistributionSetType}. + */ + String getKey(); + + /** + * @param key + * of this {@link DistributionSetType}. + */ + void setKey(String key); + + /** + * @param distributionSet + * to check for completeness + * @return true if the all mandatory software module types are + * in the system. + */ + boolean checkComplete(DistributionSet distributionSet); + + /** + * @return get color code to by used in management UI views. + */ + String getColour(); + + /** + * @param colour + * code to by used in management UI views. + */ + void setColour(final String colour); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifact.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifact.java new file mode 100644 index 000000000..7e1a965e7 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifact.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; + +import java.net.URL; + +/** + * External artifact representation with all the necessary information to + * generate an artifact {@link URL} at runtime. + * + */ +public interface ExternalArtifact extends Artifact { + + /** + * @return {@link ExternalArtifactProvider} of this {@link Artifact}. + */ + ExternalArtifactProvider getExternalArtifactProvider(); + + /** + * @return generated download {@link URL}. + */ + String getUrl(); + + /** + * @return suffix for {@link URL} generation. + */ + String getUrlSuffix(); + + /** + * @param urlSuffix + * the urlSuffix to set + */ + void setUrlSuffix(String urlSuffix); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifactProvider.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifactProvider.java new file mode 100644 index 000000000..139327096 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifactProvider.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; + +/** + * External repositories for artifact storage. The update server provides URLs + * for the targets to download from these external resources but does not access + * them itself. + * + */ +public interface ExternalArtifactProvider extends NamedEntity { + + /** + * @return prefix for url generation + */ + String getBasePath(); + + /** + * @return default for {@link ExternalArtifact#getUrlSuffix()}. + */ + String getDefaultSuffix(); + + /** + * @param basePath + * prefix for url generation + */ + void setBasePath(String basePath); + + /** + * @param defaultSuffix + * for {@link ExternalArtifact#getUrlSuffix()}. + */ + void setDefaultSuffix(String defaultSuffix); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/LocalArtifact.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/LocalArtifact.java new file mode 100644 index 000000000..9aeb791c4 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/LocalArtifact.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.model; + +import org.eclipse.hawkbit.artifact.repository.ArtifactRepository; + +/** + * Tenant specific locally stored artifact representation that is used by + * {@link SoftwareModule}s . It contains all information that is provided by the + * user while all update server generated information related to the artifact + * (hash, length) is stored directly with the binary itself in the + * {@link ArtifactRepository}. + * + */ +public interface LocalArtifact extends Artifact { + + /** + * @return the filename that was provided during upload. + */ + String getFilename(); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/MetaData.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/MetaData.java new file mode 100644 index 000000000..68b7349f9 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/MetaData.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.model; + +import java.io.Serializable; + +/** + * Meta data for entities, a (key/value) store. + * + */ +public interface MetaData extends Serializable { + + /** + * @return the key + */ + String getKey(); + + /** + * @param key + */ + void setKey(String key); + + /** + * @return the value + */ + String getValue(); + + /** + * @param value + */ + void setValue(String value); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/NamedEntity.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/NamedEntity.java new file mode 100644 index 000000000..4d3f3e419 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/NamedEntity.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.model; + +/** + * Entities that have a name and description. + * + */ +public interface NamedEntity extends TenantAwareBaseEntity { + + /** + * @return the description of the entity. + */ + String getDescription(); + + /** + * @return the name of the entity. + */ + String getName(); + + /** + * @param description + * of the entity. + */ + void setDescription(String description); + + /** + * @param name + * of the entity. + */ + void setName(String name); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/NamedVersionedEntity.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/NamedVersionedEntity.java new file mode 100644 index 000000000..b66115082 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/NamedVersionedEntity.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.model; + +/** + * Entities that have a name and a description. + * + */ +public interface NamedVersionedEntity extends NamedEntity { + + /** + * @return the version of entity. + */ + String getVersion(); + + /** + * @param version + * of the entity. + */ + void setVersion(String version); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/PollStatus.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/PollStatus.java new file mode 100644 index 000000000..876020dbd --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/PollStatus.java @@ -0,0 +1,68 @@ +/** + * 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; + +import java.time.LocalDateTime; + +/** + * The poll time object which holds all the necessary information around the + * target poll time, e.g. the last poll time, the next poll time and the overdue + * poll time. + * + */ +public class PollStatus { + private final LocalDateTime lastPollDate; + private final LocalDateTime nextPollDate; + private final LocalDateTime overdueDate; + private final LocalDateTime currentDate; + + public PollStatus(final LocalDateTime lastPollDate, final LocalDateTime nextPollDate, + final LocalDateTime overdueDate, final LocalDateTime currentDate) { + this.lastPollDate = lastPollDate; + this.nextPollDate = nextPollDate; + this.overdueDate = overdueDate; + this.currentDate = currentDate; + } + + /** + * calculates if the target poll time is overdue and the target has not been + * polled in the configured poll time interval. + * + * @return {@code true} if the current time is after the poll time overdue + * date otherwise {@code false}. + */ + public boolean isOverdue() { + return currentDate.isAfter(overdueDate); + } + + /** + * @return the lastPollDate + */ + public LocalDateTime getLastPollDate() { + return lastPollDate; + } + + public LocalDateTime getNextPollDate() { + return nextPollDate; + } + + public LocalDateTime getOverdueDate() { + return overdueDate; + } + + public LocalDateTime getCurrentDate() { + return currentDate; + } + + @Override + public String toString() { + return "PollTime [lastPollDate=" + lastPollDate + ", nextPollDate=" + nextPollDate + ", overdueDate=" + + overdueDate + ", currentDate=" + currentDate + "]"; + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RepositoryModelConstants.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RepositoryModelConstants.java new file mode 100644 index 000000000..66806915a --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RepositoryModelConstants.java @@ -0,0 +1,27 @@ +/** + * 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; + +/** + * Repository model constants. + * + */ +public final class RepositoryModelConstants { + + /** + * indicating that target action has no force time which is only needed in + * case of {@link Action.ActionType#TIMEFORCED}. + */ + public static final Long NO_FORCE_TIME = 0L; + + private RepositoryModelConstants() { + // Utility class. + } + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Rollout.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Rollout.java new file mode 100644 index 000000000..37185a8e2 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Rollout.java @@ -0,0 +1,159 @@ +/** + * 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; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.eclipse.hawkbit.repository.model.Action.ActionType; +import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus.Status; + +/** + * Software update operations in large scale IoT scenarios with hundred of + * thousands of devices require special handling. + * + * That includes secure handling of large volumes of devices at rollout creation + * time. Monitoring of the rollout progress. Emergency rollout shutdown in case + * of problems on to many devices and reporting capabilities for a complete + * understanding of the rollout progress at each point in time. + * + */ +public interface Rollout extends NamedEntity { + + /** + * @return {@link DistributionSet} that is rolled out + */ + DistributionSet getDistributionSet(); + + /** + * @param distributionSet + * that is rolled out + */ + void setDistributionSet(DistributionSet distributionSet); + + /** + * @return list of deployment groups of the rollout. + */ + List getRolloutGroups(); + + /** + * @return rsql query that identifies the targets that are part of this + * rollout. + */ + String getTargetFilterQuery(); + + /** + * @param targetFilterQuery + * that identifies the targets that are part of this rollout. + */ + void setTargetFilterQuery(String targetFilterQuery); + + /** + * @return status of the rollout + */ + RolloutStatus getStatus(); + + /** + * @return {@link ActionType} of the rollout. + */ + ActionType getActionType(); + + /** + * @param actionType + * of the rollout. + */ + void setActionType(ActionType actionType); + + /** + * @return time in {@link TimeUnit#MILLISECONDS} after which + * {@link #isForced()} switches to true in case of + * {@link ActionType#TIMEFORCED}. + */ + long getForcedTime(); + + /** + * @param forcedTime + * in {@link TimeUnit#MILLISECONDS} after which + * {@link #isForced()} switches to true in case of + * {@link ActionType#TIMEFORCED}. + */ + void setForcedTime(long forcedTime); + + /** + * @return number of {@link Target}s in this rollout. + */ + long getTotalTargets(); + + /** + * @return number of {@link RolloutGroup}s. + */ + int getRolloutGroupsCreated(); + + /** + * @return all states with the respective target count in that + * {@link Status}. + */ + TotalTargetCountStatus getTotalTargetCountStatus(); + + /** + * + * State machine for rollout. + * + */ + public enum RolloutStatus { + + /** + * Rollouts is being created. + */ + CREATING, + + /** + * Rollout is ready to start. + */ + READY, + + /** + * Rollout is paused. + */ + PAUSED, + + /** + * Rollout is starting. + */ + STARTING, + + /** + * Rollout is stopped. + */ + STOPPED, + + /** + * Rollout is running. + */ + RUNNING, + + /** + * Rollout is finished. + */ + FINISHED, + + /** + * Rollout could not be created due to errors, might be a database + * problem during asynchronous creating. + */ + ERROR_CREATING, + + /** + * Rollout could not be started due to errors, might be database problem + * during asynchronous starting. + */ + ERROR_STARTING; + } + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroup.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroup.java new file mode 100644 index 000000000..3180fdb6a --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroup.java @@ -0,0 +1,284 @@ +/** + * 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; + +/** + * The core functionality of a {@link Rollout} is the cascading processing of + * (sub) deployment groups. The group defines under which conditions the + * following group is processed. + * + */ +public interface RolloutGroup extends NamedEntity { + + /** + * @return the corresponding {@link Rollout} of this group + */ + Rollout getRollout(); + + /** + * @param rollout + * sets the {@link Rollout} for this group + */ + void setRollout(Rollout rollout); + + /** + * @return the current {@link RolloutGroupStatus} for this group + */ + RolloutGroupStatus getStatus(); + + /** + * @param status + * the {@link RolloutGroupStatus} to set for this group + */ + void setStatus(RolloutGroupStatus status); + + /** + * @return the parent group of this group, in case the group is the root + * group it does not have a parent and so return {@code null} + */ + RolloutGroup getParent(); + + /** + * @return the {@link RolloutGroupSuccessCondition} for this group to + * indicate when a group is successful + */ + RolloutGroupSuccessCondition getSuccessCondition(); + + /** + * @param successCondition + * the {@link RolloutGroupSuccessCondition} to be set for this + * group to indicate when a group is successfully and a next + * group might be started + */ + void setSuccessCondition(RolloutGroupSuccessCondition successCondition); + + /** + * @return a String representation of the expression to be evaluated by the + * {@link RolloutGroupSuccessCondition} to indicate if the condition + * is true, might be {@code null} if no expression must be set for + * the {@link RolloutGroupSuccessCondition} + */ + String getSuccessConditionExp(); + + /** + * @param successConditionExp + * sets a String represented expression which is evaluated by the + * {@link RolloutGroupSuccessCondition}, might be {@code null} if + * the set {@link RolloutGroupSuccessCondition} can handle + * {@code null} value + */ + void setSuccessConditionExp(String successConditionExp); + + /** + * @return the {@link RolloutGroupErrorCondition} for this group to indicate + * when a group should marked as failed + */ + RolloutGroupErrorCondition getErrorCondition(); + + /** + * + * @param errorCondition + * the {@link RolloutGroupErrorCondition} to be set for this + * group to indicate when a group is marked as failed and the + * corresponding {@link RolloutGroupErrorAction} should be + * executed + */ + void setErrorCondition(RolloutGroupErrorCondition errorCondition); + + /** + * @return a String representation of the expression to be evaluated by the + * {@link RolloutGroupErrorCondition} to indicate if the condition + * is true, might be {@code null} if no expression must be set for + * the {@link RolloutGroupErrorCondition} + */ + String getErrorConditionExp(); + + /** + * @param errorExp + * sets a String represented expression which is evaluated by the + * {@link RolloutGroupErrorCondition}, might be {@code null} if + * the set {@link RolloutGroupErrorCondition} can handle + * {@code null} value + */ + void setErrorConditionExp(String errorExp); + + /** + * @return a {@link RolloutGroupErrorAction} which is executed when the + * given {@link RolloutGroupErrorCondition} is met, might be + * {@code null} if no error action is set + */ + RolloutGroupErrorAction getErrorAction(); + + /** + * @param errorAction + * the {@link RolloutGroupErrorAction} to be set which should be + * executed if the {@link RolloutGroupErrorCondition} is met, + * might be {@code null} if no error action should be executed + */ + void setErrorAction(RolloutGroupErrorAction errorAction); + + /** + * @return a String representation of the expression to be evaluated by the + * {@link RolloutGroupErrorAction} might be {@code null} if no + * expression must be set for the {@link RolloutGroupErrorAction} + */ + String getErrorActionExp(); + + /** + * @param errorActionExp + * sets a String represented expression which is evaluated by the + * {@link RolloutGroupErrorAction}, might be {@code null} if the + * set {@link RolloutGroupErrorAction} can handle {@code null} + * value + */ + void setErrorActionExp(String errorActionExp); + + /** + * @return the {@link RolloutGroupSuccessAction} which is executed if the + * {@link RolloutGroupSuccessCondition} is met + */ + RolloutGroupSuccessAction getSuccessAction(); + + /** + * @return a String representation of the expression to be evaluated by the + * {@link RolloutGroupSuccessAction} might be {@code null} if no + * expression must be set for the {@link RolloutGroupSuccessAction} + */ + String getSuccessActionExp(); + + /** + * @return the total amount of targets containing in this group + */ + long getTotalTargets(); + + /** + * @return the totalTargetCountStatus + */ + TotalTargetCountStatus getTotalTargetCountStatus(); + + /** + * @param totalTargetCountStatus + * the totalTargetCountStatus to set + */ + void setTotalTargetCountStatus(TotalTargetCountStatus totalTargetCountStatus); + + /** + * Rollout goup state machine. + * + */ + public enum RolloutGroupStatus { + + /** + * Ready to start the group. + */ + READY, + + /** + * Group is scheduled and started sometime, e.g. trigger of group + * before. + */ + SCHEDULED, + + /** + * Group is finished. + */ + FINISHED, + + /** + * Group is finished and has errors. + */ + ERROR, + + /** + * Group is running. + */ + RUNNING; + } + + /** + * The condition to evaluate if an group is success state. + */ + public enum RolloutGroupSuccessCondition { + THRESHOLD("thresholdRolloutGroupSuccessCondition"); + + private final String beanName; + + private RolloutGroupSuccessCondition(final String beanName) { + this.beanName = beanName; + } + + /** + * @return the beanName + */ + public String getBeanName() { + return beanName; + } + } + + /** + * The condition to evaluate if an group is in error state. + */ + public enum RolloutGroupErrorCondition { + THRESHOLD("thresholdRolloutGroupErrorCondition"); + + private final String beanName; + + private RolloutGroupErrorCondition(final String beanName) { + this.beanName = beanName; + } + + /** + * @return the beanName + */ + public String getBeanName() { + return beanName; + } + } + + /** + * The actions executed when the {@link RolloutGroup#errorCondition} is hit. + */ + public enum RolloutGroupErrorAction { + PAUSE("pauseRolloutGroupAction"); + + private final String beanName; + + private RolloutGroupErrorAction(final String beanName) { + this.beanName = beanName; + } + + /** + * @return the beanName + */ + public String getBeanName() { + return beanName; + } + } + + /** + * The actions executed when the {@link RolloutGroup#successCondition} is + * hit. + */ + public enum RolloutGroupSuccessAction { + NEXTGROUP("startNextRolloutGroupAction"); + + private final String beanName; + + private RolloutGroupSuccessAction(final String beanName) { + this.beanName = beanName; + } + + /** + * @return the beanName + */ + public String getBeanName() { + return beanName; + } + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroupConditionBuilder.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroupConditionBuilder.java new file mode 100644 index 000000000..7ef8c8a19 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroupConditionBuilder.java @@ -0,0 +1,91 @@ +/** + * 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; + +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessAction; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; + +/** + * Builder to build easily the {@link RolloutGroupConditions}. + * + */ +public class RolloutGroupConditionBuilder { + private final RolloutGroupConditions conditions = new RolloutGroupConditions(); + + /** + * @return completed {@link RolloutGroupConditions}. + */ + public RolloutGroupConditions build() { + return conditions; + } + + /** + * Sets the finish condition and expression on the builder. + * + * @param condition + * the finish condition + * @param expression + * the finish expression + * @return the builder itself + */ + public RolloutGroupConditionBuilder successCondition(final RolloutGroupSuccessCondition condition, + final String expression) { + conditions.setSuccessCondition(condition); + conditions.setSuccessConditionExp(expression); + return this; + } + + /** + * Sets the success action and expression on the builder. + * + * @param action + * the success action + * @param expression + * the error expression + * @return the builder itself + */ + public RolloutGroupConditionBuilder successAction(final RolloutGroupSuccessAction action, final String expression) { + conditions.setSuccessAction(action); + conditions.setSuccessActionExp(expression); + return this; + } + + /** + * Sets the error condition and expression on the builder. + * + * @param condition + * the error condition + * @param expression + * the error expression + * @return the builder itself + */ + public RolloutGroupConditionBuilder errorCondition(final RolloutGroupErrorCondition condition, + final String expression) { + conditions.setErrorCondition(condition); + conditions.setErrorConditionExp(expression); + return this; + } + + /** + * Sets the error action and expression on the builder. + * + * @param action + * the error action + * @param expression + * the error expression + * @return the builder itself + */ + public RolloutGroupConditionBuilder errorAction(final RolloutGroupErrorAction action, final String expression) { + conditions.setErrorAction(action); + conditions.setErrorActionExp(expression); + return this; + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroupConditions.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroupConditions.java new file mode 100644 index 000000000..618e93c4e --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroupConditions.java @@ -0,0 +1,93 @@ +/** + * 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; + +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessAction; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; + +/** + * Object which holds all {@link RolloutGroup} conditions together which can + * easily built. + */ +public class RolloutGroupConditions { + private RolloutGroupSuccessCondition successCondition; + private String successConditionExp; + private RolloutGroupSuccessAction successAction; + private String successActionExp; + private RolloutGroupErrorCondition errorCondition; + private String errorConditionExp; + private RolloutGroupErrorAction errorAction; + private String errorActionExp; + + public RolloutGroupSuccessCondition getSuccessCondition() { + return successCondition; + } + + public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) { + successCondition = finishCondition; + } + + public String getSuccessConditionExp() { + return successConditionExp; + } + + public void setSuccessConditionExp(final String finishConditionExp) { + successConditionExp = finishConditionExp; + } + + public RolloutGroupSuccessAction getSuccessAction() { + return successAction; + } + + public void setSuccessAction(final RolloutGroupSuccessAction successAction) { + this.successAction = successAction; + } + + public String getSuccessActionExp() { + return successActionExp; + } + + public void setSuccessActionExp(final String successActionExp) { + this.successActionExp = successActionExp; + } + + public RolloutGroupErrorCondition getErrorCondition() { + return errorCondition; + } + + public void setErrorCondition(final RolloutGroupErrorCondition errorCondition) { + this.errorCondition = errorCondition; + } + + public String getErrorConditionExp() { + return errorConditionExp; + } + + public void setErrorConditionExp(final String errorConditionExp) { + this.errorConditionExp = errorConditionExp; + } + + public RolloutGroupErrorAction getErrorAction() { + return errorAction; + } + + public void setErrorAction(final RolloutGroupErrorAction errorAction) { + this.errorAction = errorAction; + } + + public String getErrorActionExp() { + return errorActionExp; + } + + public void setErrorActionExp(final String errorActionExp) { + this.errorActionExp = errorActionExp; + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModule.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModule.java new file mode 100644 index 000000000..3c3a24fd0 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModule.java @@ -0,0 +1,111 @@ +/** + * 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; + +import java.util.List; +import java.util.Optional; + +public interface SoftwareModule extends NamedVersionedEntity { + + /** + * @param artifact + * is added to the assigned {@link Artifact}s. + */ + void addArtifact(LocalArtifact artifact); + + /** + * @param artifact + * is added to the assigned {@link Artifact}s. + */ + void addArtifact(ExternalArtifact artifact); + + /** + * @param artifactId + * to look for + * @return found {@link Artifact} + */ + Optional getLocalArtifact(Long artifactId); + + /** + * @param fileName + * to look for + * @return found {@link Artifact} + */ + Optional getLocalArtifactByFilename(String fileName); + + /** + * @return the artifacts + */ + List getArtifacts(); + + /** + * @return local artifacts only + */ + List getLocalArtifacts(); + + /** + * @return the vendor of this software module + */ + String getVendor(); + + /** + * @param vendor + * the vendor of this software module to set + */ + void setVendor(String vendor); + + /** + * @param artifact + * is removed from the assigned {@link LocalArtifact}s. + */ + void removeArtifact(LocalArtifact artifact); + + /** + * @param artifact + * is removed from the assigned {@link ExternalArtifact}s. + */ + void removeArtifact(ExternalArtifact artifact); + + /** + * @return the type of the software module + */ + SoftwareModuleType getType(); + + /** + * @return {@code true} if this software module is marked as deleted + * otherwise {@code false} + */ + boolean isDeleted(); + + /** + * Marks or un-marks this software module as deleted. + * + * @param deleted + * {@code true} if the software module should be marked as + * deleted otherwise {@code false} + */ + void setDeleted(boolean deleted); + + /** + * @param type + * the module type for this software module + */ + void setType(SoftwareModuleType type); + + /** + * @return immutable list of meta data elements. + */ + List getMetadata(); + + /** + * @return the assignedTo + */ + List getAssignedTo(); + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleIdName.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleIdName.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleIdName.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleIdName.java diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleMetadata.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleMetadata.java new file mode 100644 index 000000000..ebfea9c28 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleMetadata.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.model; + +/** + * {@link MetaData} element of a {@link SoftwareModule}. + * + */ +public interface SoftwareModuleMetadata extends MetaData { + + /** + * @return {@link SoftwareModule} this entry belongs to. + */ + SoftwareModule getSoftwareModule(); + + /** + * @param softwareModule + * this entry belongs to. + */ + void setSoftwareModule(SoftwareModule softwareModule); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleType.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleType.java new file mode 100644 index 000000000..4bd52f3f0 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleType.java @@ -0,0 +1,60 @@ +/** + * 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; + +/** + * {@link SoftwareModuleType} is an abstract definition used in + * {@link DistributionSetType}s and includes additional {@link SoftwareModule} + * specific information. + * + */ +public interface SoftwareModuleType extends NamedEntity { + + /** + * @return business key of this {@link SoftwareModuleType}. + */ + String getKey(); + + /** + * @param key + * of this {@link SoftwareModuleType}. + */ + void setKey(String key); + + /** + * @return maximum assignments of an {@link SoftwareModule} of this type to + * a {@link DistributionSet}. + */ + int getMaxAssignments(); + + /** + * @param maxAssignments + * of an {@link SoftwareModule} of this type to a + * {@link DistributionSet}. + */ + void setMaxAssignments(int maxAssignments); + + /** + * @return true if the type is deleted and only kept for + * history purposes. + */ + boolean isDeleted(); + + /** + * @return get color code to by used in management UI views. + */ + String getColour(); + + /** + * @param colour + * code to by used in management UI views. + */ + void setColour(final String colour); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Tag.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Tag.java new file mode 100644 index 000000000..bfade80e8 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Tag.java @@ -0,0 +1,27 @@ +/** + * 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; + +/** + * {@link Tag} entry. + * + */ +public interface Tag extends NamedEntity { + + /** + * @return colour code of the tag used in Management UI. + */ + String getColour(); + + /** + * @param colour + */ + void setColour(String colour); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Target.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Target.java new file mode 100644 index 000000000..c09b28a2f --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Target.java @@ -0,0 +1,67 @@ +/** + * 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; + +import java.util.List; +import java.util.Set; + +/** + *

+ * The {@link Target} is the target of all provisioning operations. It contains + * the currently installed {@link DistributionSet} (i.e. current state). In + * addition it holds the target {@link DistributionSet} that has to be + * provisioned next (i.e. target state). + *

+ */ +public interface Target extends NamedEntity { + + /** + * @return currently assigned {@link DistributionSet}. + */ + DistributionSet getAssignedDistributionSet(); + + /** + * @return business identifier of the {@link Target} + */ + String getControllerId(); + + /** + * @return assigned {@link TargetTag}s. + */ + Set getTags(); + + /** + * @return {@link Action} history of the {@link Target}. + */ + List getActions(); + + /** + * @return {@link TargetIdName} view of the {@link Target}. + */ + default TargetIdName getTargetIdName() { + return new TargetIdName(getId(), getControllerId(), getName()); + } + + /** + * @return the targetInfo object + */ + TargetInfo getTargetInfo(); + + /** + * @return the securityToken + */ + String getSecurityToken(); + + /** + * @param token + * new securityToken + */ + void setSecurityToken(String token); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetFilterQuery.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetFilterQuery.java new file mode 100644 index 000000000..5052a0060 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetFilterQuery.java @@ -0,0 +1,59 @@ +/** + * 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; + +/** + * Managed filter entity. + * + * Supported operators. + *
    + *
  • Equal to : ==
  • + *
  • Not equal to : !=
  • + *
  • Less than : =lt= or <
  • + *
  • Less than or equal to : =le= or <=
  • + *
  • Greater than operator : =gt= or >
  • + *
  • Greater than or equal to : =ge= or >=
  • + *
+ * Examples of RSQL expressions in both FIQL-like and alternative notation: + *
    + *
  • version==2.0.0
  • + *
  • name==targetId1;description==plugAndPlay
  • + *
  • name==targetId1 and description==plugAndPlay
  • + *
  • name==targetId1;description==plugAndPlay
  • + *
  • name==targetId1 and description==plugAndPlay
  • + *
  • name==targetId1,description==plugAndPlay,updateStatus==UNKNOWN
  • + *
  • name==targetId1 or description==plugAndPlay or updateStatus==UNKNOWN
  • + *
+ * + */ +public interface TargetFilterQuery extends TenantAwareBaseEntity { + + /** + * @return name of the {@link TargetFilterQuery}. + */ + String getName(); + + /** + * @param name + * of the {@link TargetFilterQuery}. + */ + void setName(String name); + + /** + * @return RSQL query + */ + String getQuery(); + + /** + * @param query + * in RSQL notation. + */ + void setQuery(String query); + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetIdName.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetIdName.java similarity index 96% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetIdName.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetIdName.java index 26a74e9bb..444874581 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetIdName.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetIdName.java @@ -60,6 +60,8 @@ public class TargetIdName implements Serializable { } @Override + // Exception squid:S864 - generated code + @SuppressWarnings("squid:S864") public int hashCode() { final int prime = 31; int result = 1; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetInfo.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetInfo.java new file mode 100644 index 000000000..2eb2f05c7 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetInfo.java @@ -0,0 +1,80 @@ +/** + * 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; + +import java.io.Serializable; +import java.net.URI; +import java.text.AttributedCharacterIterator; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public interface TargetInfo extends Serializable { + /** + * @return the address under which the target can be reached + */ + URI getAddress(); + + /** + * @param address + * the target address to set + * + * @throws IllegalArgumentException + * If the given string violates RFC 2396 + */ + void setAddress(String address); + + /** + * @return {@link Target} this info element belongs to. + */ + Target getTarget(); + + /** + * @return time in {@link TimeUnit#MILLISECONDS} GMT when the {@link Target} + * polled the server the last time. + */ + Long getLastTargetQuery(); + + /** + * @return {@link AttributedCharacterIterator} that have been provided by + * the {@link Target} itself, e.g. hardware revision, serial number, + * mac address etc. + */ + Map getControllerAttributes(); + + /** + * @return time in {@link TimeUnit#MILLISECONDS} GMT when + * {@link #getInstalledDistributionSet()} was applied. + */ + Long getInstallationDate(); + + /** + * @return current status of the {@link Target}. + */ + TargetUpdateStatus getUpdateStatus(); + + /** + * @return currently installed {@link DistributionSet}. + */ + DistributionSet getInstalledDistributionSet(); + + /** + * @return the poll time which holds the last poll time of the target, the + * next poll time and the overdue time. In case the + * {@link #lastTargetQuery} is not set e.g. the target never polled + * before this method returns {@code null} + */ + PollStatus getPollStatus(); + + /** + * @return true if the {@link Target} has not jet provided + * {@link #getControllerAttributes()}. + */ + boolean isRequestControllerAttributes(); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetTag.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetTag.java new file mode 100644 index 000000000..f222e9e90 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetTag.java @@ -0,0 +1,24 @@ +/** + * 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; + +import java.util.List; + +/** + * Target tag element. + * + */ +public interface TargetTag extends Tag { + + /** + * @return {@link List} of targets assigned to this {@link Tag}. + */ + List getAssignedToTargets(); + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetTagAssignmentResult.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetTagAssignmentResult.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetTagAssignmentResult.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetTagAssignmentResult.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetUpdateStatus.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetUpdateStatus.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetUpdateStatus.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetUpdateStatus.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionStatus.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionStatus.java similarity index 93% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionStatus.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionStatus.java index ec09da3d5..9193b47ef 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionStatus.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionStatus.java @@ -12,14 +12,14 @@ import org.eclipse.hawkbit.repository.model.Action.Status; /** * - * Rollout - Target with action status. + * Target with action status. * */ public class TargetWithActionStatus { private Target target; - private Status status = null;; + private Status status; public TargetWithActionStatus(final Target target) { this.target = target; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetWithActionType.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionType.java similarity index 83% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetWithActionType.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionType.java index 18efa23a9..a9cfa81d1 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetWithActionType.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionType.java @@ -6,14 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.model; -import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; /** - * A custom JPA database return value object with the proper constructor so JPA - * is able to parse the result-set directly into this object. + * A custom view on {@link Target} with {@link ActionType}. * * * @@ -53,7 +51,7 @@ public class TargetWithActionType { if (actionType == ActionType.TIMEFORCED) { return forceTime; } - return Action.NO_FORCE_TIME; + return RepositoryModelConstants.NO_FORCE_TIME; } /** diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantAwareBaseEntity.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantAwareBaseEntity.java new file mode 100644 index 000000000..8c19db236 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantAwareBaseEntity.java @@ -0,0 +1,22 @@ +/** + * 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; + +/** + * {@link BaseEntity} that distinguishes between tenants. + * + */ +public interface TenantAwareBaseEntity extends BaseEntity { + + /** + * @return tenant name + */ + String getTenant(); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfiguration.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfiguration.java new file mode 100644 index 000000000..fdbc5c8d3 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfiguration.java @@ -0,0 +1,40 @@ +/** + * 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; + +/** + * Unstructured tenant configuration elements. Can be used to store arbitrary + * tenant configuration elements. + * + */ +public interface TenantConfiguration extends TenantAwareBaseEntity { + + /** + * @return key of the entry + */ + String getKey(); + + /** + * @param key + * of the entry + */ + void setKey(String key); + + /** + * @return value of the entry + */ + String getValue(); + + /** + * @param value + * of the entry + */ + void setValue(String value); + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfigurationValue.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfigurationValue.java similarity index 94% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfigurationValue.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfigurationValue.java index 37e00e247..a204ef506 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfigurationValue.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfigurationValue.java @@ -14,14 +14,14 @@ package org.eclipse.hawkbit.repository.model; * @param * type of the configuration value */ -public class TenantConfigurationValue { +public final class TenantConfigurationValue { private T value; private Long lastModifiedAt; private String lastModifiedBy; private Long createdAt; private String createdBy; - private boolean isGlobal = true; + private boolean global = true; private TenantConfigurationValue() { } @@ -41,7 +41,7 @@ public class TenantConfigurationValue { * @return true, if is global */ public boolean isGlobal() { - return isGlobal; + return global; } /** @@ -126,13 +126,13 @@ public class TenantConfigurationValue { /** * set the is global attribute. * - * @param isGlobal + * @param global * true when there is no tenant specific value, false * otherwise * @return the tenant configuration value builder */ - public TenantConfigurationValueBuilder isGlobal(final boolean isGlobal) { - this.configuration.isGlobal = isGlobal; + public TenantConfigurationValueBuilder global(final boolean global) { + this.configuration.global = global; return this; } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantMetaData.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantMetaData.java new file mode 100644 index 000000000..0b40d9939 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantMetaData.java @@ -0,0 +1,34 @@ +/** + * 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; + +/** + * MetaData of a tenant account. + * + */ +public interface TenantMetaData extends BaseEntity { + + /** + * @return default {@link DistributionSetType}. + */ + DistributionSetType getDefaultDsType(); + + /** + * @param defaultDsType + * that is used of none is selected for a new + * {@link DistributionSet}. + */ + void setDefaultDsType(DistributionSetType defaultDsType); + + /** + * @return tenant name + */ + String getTenant(); + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountActionStatus.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountActionStatus.java similarity index 100% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountActionStatus.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountActionStatus.java diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountStatus.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountStatus.java similarity index 62% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountStatus.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountStatus.java index 13c41baf3..bcb0df3f4 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountStatus.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountStatus.java @@ -15,7 +15,8 @@ import java.util.Map; /** * - * Store all states with the target count of a rollout or rolloutgroup. + * Store target count of a {@link Rollout} or {@link RolloutGroup} for every + * {@link Status}. * */ public class TotalTargetCountStatus { @@ -24,7 +25,35 @@ public class TotalTargetCountStatus { * Status of the total target counts. */ public enum Status { - SCHEDULED, RUNNING, ERROR, FINISHED, CANCELLED, NOTSTARTED + /** + * Action is scheduled. + */ + SCHEDULED, + + /** + * Action is still running. + */ + RUNNING, + + /** + * Action failed. + */ + ERROR, + + /** + * Action is completed. + */ + FINISHED, + + /** + * Action is canceled. + */ + CANCELLED, + + /** + * Action is not started yet. + */ + NOTSTARTED } private final Map statusTotalCountMap = new EnumMap<>(Status.class); @@ -35,7 +64,7 @@ public class TotalTargetCountStatus { * * @param targetCountActionStatus * the action state map - * @param totalTargets + * @param totalTargetCount * the total target count */ public TotalTargetCountStatus(final List targetCountActionStatus, @@ -81,8 +110,7 @@ public class TotalTargetCountStatus { * @param statusTotalCountMap * the map * @param rolloutStatusCountItems - * all target statut with total count - * @return some state is populated nothing is happend + * all target {@link Status} with total count */ private final void mapActionStatusToTotalTargetCountStatus( final List targetCountActionStatus) { @@ -93,33 +121,40 @@ public class TotalTargetCountStatus { statusTotalCountMap.put(Status.RUNNING, 0L); Long notStartedTargetCount = totalTargetCount; for (final TotalTargetCountActionStatus item : targetCountActionStatus) { - switch (item.getStatus()) { - case SCHEDULED: - statusTotalCountMap.put(Status.SCHEDULED, item.getCount()); - break; - case ERROR: - statusTotalCountMap.put(Status.ERROR, item.getCount()); - break; - case FINISHED: - statusTotalCountMap.put(Status.FINISHED, item.getCount()); - break; - case RETRIEVED: - case RUNNING: - case WARNING: - case DOWNLOAD: - case CANCELING: - final Long runningItemsCount = statusTotalCountMap.get(Status.RUNNING) + item.getCount(); - statusTotalCountMap.put(Status.RUNNING, runningItemsCount); - break; - case CANCELED: - statusTotalCountMap.put(Status.CANCELLED, item.getCount()); - break; - default: - throw new IllegalArgumentException("State " + item.getStatus() + "is not valid"); - } + convertStatus(item); notStartedTargetCount -= item.getCount(); } statusTotalCountMap.put(TotalTargetCountStatus.Status.NOTSTARTED, notStartedTargetCount); } + // Exception squid:MethodCyclomaticComplexity - simple state conversion, not + // really complex. + @SuppressWarnings("squid:MethodCyclomaticComplexity") + private void convertStatus(final TotalTargetCountActionStatus item) { + switch (item.getStatus()) { + case SCHEDULED: + statusTotalCountMap.put(Status.SCHEDULED, item.getCount()); + break; + case ERROR: + statusTotalCountMap.put(Status.ERROR, item.getCount()); + break; + case FINISHED: + statusTotalCountMap.put(Status.FINISHED, item.getCount()); + break; + case RETRIEVED: + case RUNNING: + case WARNING: + case DOWNLOAD: + case CANCELING: + final Long runningItemsCount = statusTotalCountMap.get(Status.RUNNING) + item.getCount(); + statusTotalCountMap.put(Status.RUNNING, runningItemsCount); + break; + case CANCELED: + statusTotalCountMap.put(Status.CANCELLED, item.getCount()); + break; + default: + throw new IllegalArgumentException("State " + item.getStatus() + "is not valid"); + } + } + } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/AbstractReportSeries.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/AbstractReportSeries.java similarity index 94% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/AbstractReportSeries.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/AbstractReportSeries.java index 0542f68c9..747cd8279 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/AbstractReportSeries.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/AbstractReportSeries.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.report.model; +package org.eclipse.hawkbit.repository.report.model; import java.io.Serializable; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeries.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/DataReportSeries.java similarity index 97% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeries.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/DataReportSeries.java index 39c8f5723..e9fb032c3 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeries.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/DataReportSeries.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.report.model; +package org.eclipse.hawkbit.repository.report.model; import java.io.Serializable; import java.util.ArrayList; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeriesItem.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/DataReportSeriesItem.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeriesItem.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/DataReportSeriesItem.java index 492e27e1e..7dba6c082 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeriesItem.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/DataReportSeriesItem.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.report.model; +package org.eclipse.hawkbit.repository.report.model; import java.io.Serializable; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/InnerOuterDataReportSeries.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/InnerOuterDataReportSeries.java similarity index 96% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/InnerOuterDataReportSeries.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/InnerOuterDataReportSeries.java index b63935b39..357f9a554 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/InnerOuterDataReportSeries.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/InnerOuterDataReportSeries.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.report.model; +package org.eclipse.hawkbit.repository.report.model; import java.io.Serializable; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/ListReportSeries.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/ListReportSeries.java similarity index 96% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/ListReportSeries.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/ListReportSeries.java index 79c496480..18b011420 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/ListReportSeries.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/ListReportSeries.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.report.model; +package org.eclipse.hawkbit.repository.report.model; import java.util.ArrayList; import java.util.Collections; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/SeriesTime.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/SeriesTime.java similarity index 93% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/SeriesTime.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/SeriesTime.java index a50171479..0ab466acd 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/SeriesTime.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/SeriesTime.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.report.model; +package org.eclipse.hawkbit.repository.report.model; /** * A series time enum definition for {@link DataReportSeriesItem}s. diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/SystemUsageReport.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/SystemUsageReport.java similarity index 97% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/SystemUsageReport.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/SystemUsageReport.java index 45cc60cba..fe6c6bb96 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/SystemUsageReport.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/SystemUsageReport.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.report.model; +package org.eclipse.hawkbit.repository.report.model; import java.util.ArrayList; import java.util.List; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/TenantUsage.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/TenantUsage.java similarity index 91% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/TenantUsage.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/TenantUsage.java index d0ee7102c..933ca564b 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/TenantUsage.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/report/model/TenantUsage.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.report.model; +package org.eclipse.hawkbit.repository.report.model; /** * System usage stats element for a tenant. @@ -106,7 +106,7 @@ public class TenantUsage { } @Override - public int hashCode() { // NOSONAR - as this is generated code + public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (actions ^ (actions >>> 32)); @@ -118,15 +118,14 @@ public class TenantUsage { } @Override - public boolean equals(final Object obj) { // NOSONAR - as this is generated - // code + public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } - if (getClass() != obj.getClass()) { + if (!(obj instanceof TenantUsage)) { return false; } final TenantUsage other = (TenantUsage) obj; @@ -154,7 +153,7 @@ public class TenantUsage { @Override public String toString() { - return "SystemUsage [tenantName=" + tenantName + ", targets=" + targets + ", artifacts=" + artifacts + return "TenantUsage [tenantName=" + tenantName + ", targets=" + targets + ", artifacts=" + artifacts + ", actions=" + actions + ", overallArtifactVolumeInBytes=" + overallArtifactVolumeInBytes + "]"; } diff --git a/hawkbit-repository/hawkbit-repository-core/README.md b/hawkbit-repository/hawkbit-repository-core/README.md new file mode 100644 index 000000000..6973d7406 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-core/README.md @@ -0,0 +1,3 @@ +# hawkBit common implementation + +Core elements that can be used by implementations. \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-core/pom.xml b/hawkbit-repository/hawkbit-repository-core/pom.xml new file mode 100644 index 000000000..77e20cf3c --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-core/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + org.eclipse.hawkbit + hawkbit-repository + 0.2.0-SNAPSHOT + + hawkbit-repository-core + hawkBit :: Repository Core Implementation Support + + + + org.eclipse.hawkbit + hawkbit-repository-api + ${project.version} + + + + \ No newline at end of file diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/EventBusHolder.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EventBusHolder.java similarity index 87% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/EventBusHolder.java rename to hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EventBusHolder.java index 8111a1c28..3829d639b 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/EventBusHolder.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EventBusHolder.java @@ -6,9 +6,8 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model.helper; +package org.eclipse.hawkbit.repository.jpa.model.helper; -import org.eclipse.hawkbit.eventbus.CacheFieldEntityListener; import org.springframework.beans.factory.annotation.Autowired; import com.google.common.eventbus.EventBus; @@ -16,7 +15,7 @@ import com.google.common.eventbus.EventBus; /** * A singleton bean which holds the {@link EventBus} to have to the cache * manager in beans not instantiated by spring e.g. JPA entities or - * {@link CacheFieldEntityListener} which cannot be autowired. + * CacheFieldEntityListener which cannot be autowired. * */ public final class EventBusHolder { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SystemManagementHolder.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SystemManagementHolder.java similarity index 96% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SystemManagementHolder.java rename to hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SystemManagementHolder.java index d1327c690..1b1fbb091 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SystemManagementHolder.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SystemManagementHolder.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model.helper; +package org.eclipse.hawkbit.repository.jpa.model.helper; import org.eclipse.hawkbit.repository.SystemManagement; import org.springframework.beans.factory.annotation.Autowired; diff --git a/hawkbit-repository/hawkbit-repository-jpa/.gitignore b/hawkbit-repository/hawkbit-repository-jpa/.gitignore new file mode 100644 index 000000000..ae3c17260 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/hawkbit-repository/hawkbit-repository-jpa/README.md b/hawkbit-repository/hawkbit-repository-jpa/README.md new file mode 100644 index 000000000..6dd0217e7 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/README.md @@ -0,0 +1,3 @@ +# hawkBit JPA implementation + +JPA implementation of the repository. Based on [EclipseLink](http://www.eclipse.org/eclipselink/) and [Spring Data Jpa](http://projects.spring.io/spring-data-jpa/). \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/pom.xml b/hawkbit-repository/hawkbit-repository-jpa/pom.xml new file mode 100644 index 000000000..bd56e9ca5 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/pom.xml @@ -0,0 +1,207 @@ + + + 4.0.0 + + org.eclipse.hawkbit + 0.2.0-SNAPSHOT + hawkbit-repository + + hawkbit-repository-jpa + hawkBit :: Repository JPA Implementation + + + + + com.ethlo.eclipselink.tools + http://ethlo.com/maven + + + + + + com.ethlo.eclipselink.tools + http://ethlo.com/maven + + + + + + + + org.eclipse.hawkbit + hawkbit-repository-api + ${project.version} + + + org.eclipse.hawkbit + hawkbit-repository-core + ${project.version} + + + org.eclipse.hawkbit + hawkbit-artifact-repository-mongo + ${project.version} + + + com.google.guava + guava + + + org.springframework.boot + spring-boot + + + org.springframework.boot + spring-boot-starter-logging + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.eclipse.persistence + org.eclipse.persistence.jpa + + + org.springframework.security + spring-security-core + + + org.flywaydb + flyway-core + + + org.springframework.boot + spring-boot-configuration-processor + true + + + cz.jirutka.rsql + rsql-parser + + + + + org.eclipse.hawkbit + hawkbit-repository-test + ${project.version} + test + + + com.fasterxml.jackson.core + jackson-core + test + + + com.fasterxml.jackson.core + jackson-databind + test + + + com.h2database + h2 + test + + + org.mariadb.jdbc + mariadb-java-client + test + + + javax.el + javax.el-api + test + + + ru.yandex.qatools.allure + allure-junit-adaptor + test + + + org.easytesting + fest-assert-core + test + + + org.easytesting + fest-assert + test + + + + + + + org.bsc.maven + maven-processor-plugin + + + process + + process + + generate-sources + + + org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor + + + + + + + org.hibernate + hibernate-jpamodelgen + ${hibernate.version} + + + + + + com.ethlo.persistence.tools + eclipselink-maven-plugin + 2.6.2 + + + process-classes + + weave + + + + + + org.eclipse.persistence + org.eclipse.persistence.jpa + ${eclipselink.version} + + + org.javassist + javassist + 3.20.0-GA + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + + diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/EnableRestResources.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/EnableJpaRepository.java similarity index 84% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/EnableRestResources.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/EnableJpaRepository.java index 8f9952054..55fd4a111 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/EnableRestResources.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/EnableJpaRepository.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -15,20 +15,18 @@ import java.lang.annotation.Target; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.stereotype.Controller; /** * Annotation to enable {@link ComponentScan} in the resource package to setup * all {@link Controller} annotated classes and setup the REST-Resources for the * Management API. - * - * - * */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Configuration -@ComponentScan -public @interface EnableRestResources { +@Import(RepositoryApplicationConfiguration.class) +public @interface EnableJpaRepository { } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java new file mode 100644 index 000000000..7236cbe79 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java @@ -0,0 +1,384 @@ +/** + * 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; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.hawkbit.repository.ArtifactManagement; +import org.eclipse.hawkbit.repository.ControllerManagement; +import org.eclipse.hawkbit.repository.DeploymentManagement; +import org.eclipse.hawkbit.repository.DistributionSetManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.ReportManagement; +import org.eclipse.hawkbit.repository.RepositoryProperties; +import org.eclipse.hawkbit.repository.RolloutGroupManagement; +import org.eclipse.hawkbit.repository.RolloutManagement; +import org.eclipse.hawkbit.repository.SoftwareManagement; +import org.eclipse.hawkbit.repository.SystemManagement; +import org.eclipse.hawkbit.repository.TagManagement; +import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; +import org.eclipse.hawkbit.repository.TargetManagement; +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.TenantStatsManagement; +import org.eclipse.hawkbit.repository.jpa.JpaArtifactManagement; +import org.eclipse.hawkbit.repository.jpa.JpaControllerManagement; +import org.eclipse.hawkbit.repository.jpa.JpaDeploymentManagement; +import org.eclipse.hawkbit.repository.jpa.JpaDistributionSetManagement; +import org.eclipse.hawkbit.repository.jpa.JpaEntityFactory; +import org.eclipse.hawkbit.repository.jpa.JpaReportManagement; +import org.eclipse.hawkbit.repository.jpa.JpaRolloutGroupManagement; +import org.eclipse.hawkbit.repository.jpa.JpaRolloutManagement; +import org.eclipse.hawkbit.repository.jpa.JpaSoftwareManagement; +import org.eclipse.hawkbit.repository.jpa.JpaSystemManagement; +import org.eclipse.hawkbit.repository.jpa.JpaTagManagement; +import org.eclipse.hawkbit.repository.jpa.JpaTargetFilterQueryManagement; +import org.eclipse.hawkbit.repository.jpa.JpaTargetManagement; +import org.eclipse.hawkbit.repository.jpa.JpaTenantConfigurationManagement; +import org.eclipse.hawkbit.repository.jpa.JpaTenantStatsManagement; +import org.eclipse.hawkbit.repository.jpa.aspects.ExceptionMappingAspectHandler; +import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.CacheManagerHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.SystemManagementHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder; +import org.eclipse.hawkbit.security.SecurityTokenGenerator; +import org.eclipse.hawkbit.security.SystemSecurityContext; +import org.eclipse.hawkbit.tenancy.TenantAware; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; +import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; + +import com.google.common.eventbus.EventBus; + +/** + * General configuration for hawkBit's Repository. + * + */ +@EnableJpaRepositories(basePackages = { "org.eclipse.hawkbit.repository.jpa" }) +@EnableTransactionManagement +@EnableJpaAuditing +@EnableAspectJAutoProxy +@Configuration +@ComponentScan +@EnableAutoConfiguration +@EnableConfigurationProperties(RepositoryProperties.class) +@EnableScheduling +public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { + @Autowired + private EventBus eventBus; + + /** + * @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 TenantConfigurationManagementHolder tenantConfigurationManagementHolder() { + return TenantConfigurationManagementHolder.getInstance(); + } + + /** + * @return the {@link SystemManagementHolder} singleton bean which holds the + * current {@link SystemManagement} service and make it accessible + * in beans which cannot access the service directly, e.g. JPA + * entities. + */ + @Bean + public SystemManagementHolder systemManagementHolder() { + return SystemManagementHolder.getInstance(); + } + + /** + * @return the {@link TenantAwareHolder} singleton bean which holds the + * current {@link TenantAware} service and make it accessible in + * beans which cannot access the service directly, e.g. JPA + * entities. + */ + @Bean + public TenantAwareHolder tenantAwareHolder() { + return TenantAwareHolder.getInstance(); + } + + /** + * @return the {@link SecurityTokenGeneratorHolder} singleton bean which + * holds the current {@link SecurityTokenGenerator} service and make + * it accessible in beans which cannot access the service via + * injection + */ + @Bean + public SecurityTokenGeneratorHolder securityTokenGeneratorHolder() { + return SecurityTokenGeneratorHolder.getInstance(); + } + + /** + * @return the singleton instance of the {@link CacheManagerHolder} + */ + @Bean + public CacheManagerHolder cacheManagerHolder() { + return CacheManagerHolder.getInstance(); + } + + /** + * + * @return the singleton instance of the + * {@link AfterTransactionCommitExecutorHolder} + */ + @Bean + public AfterTransactionCommitExecutorHolder afterTransactionCommitExecutorHolder() { + return AfterTransactionCommitExecutorHolder.getInstance(); + } + + /** + * Defines the validation processor bean. + * + * @return the {@link MethodValidationPostProcessor} + */ + @Bean + public MethodValidationPostProcessor methodValidationPostProcessor() { + return new MethodValidationPostProcessor(); + } + + /** + * @return {@link ExceptionMappingAspectHandler} aspect bean + */ + @Bean + public ExceptionMappingAspectHandler createRepositoryExceptionHandlerAdvice() { + return new ExceptionMappingAspectHandler(); + } + + @Override + protected AbstractJpaVendorAdapter createJpaVendorAdapter() { + return new EclipseLinkJpaVendorAdapter(); + } + + @Override + protected Map getVendorProperties() { + + final Map properties = new HashMap<>(); + // Turn off dynamic weaving to disable LTW lookup in static weaving mode + properties.put("eclipselink.weaving", "false"); + // needed for reports + properties.put("eclipselink.jdbc.allow-native-sql-queries", "true"); + // flyway + properties.put("eclipselink.ddl-generation", "none"); + + properties.put("eclipselink.persistence-context.flush-mode", "auto"); + properties.put("eclipselink.logging.logger", "JavaLogger"); + + return properties; + } + + /** + * {@link MultiTenantJpaTransactionManager} bean. + * + * @see org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration#transactionManager() + * @return a new {@link PlatformTransactionManager} + */ + @Override + @Bean + public PlatformTransactionManager transactionManager() { + return new MultiTenantJpaTransactionManager(); + } + + /** + * {@link JpaSystemManagement} bean. + * + * @return a new {@link SystemManagement} + */ + @Bean + @ConditionalOnMissingBean + public SystemManagement systemManagement() { + return new JpaSystemManagement(); + } + + /** + * {@link JpaReportManagement} bean. + * + * @return a new {@link ReportManagement} + */ + @Bean + @ConditionalOnMissingBean + public ReportManagement reportManagement() { + return new JpaReportManagement(); + } + + /** + * {@link JpaDistributionSetManagement} bean. + * + * @return a new {@link DistributionSetManagement} + */ + @Bean + @ConditionalOnMissingBean + public DistributionSetManagement distributionSetManagement() { + return new JpaDistributionSetManagement(); + } + + /** + * {@link JpaTenantStatsManagement} bean. + * + * @return a new {@link TenantStatsManagement} + */ + @Bean + @ConditionalOnMissingBean + public TenantStatsManagement tenantStatsManagement() { + final TenantStatsManagement mgmt = new JpaTenantStatsManagement(); + eventBus.register(mgmt); + return mgmt; + } + + /** + * {@link JpaTenantConfigurationManagement} bean. + * + * @return a new {@link TenantConfigurationManagement} + */ + @Bean + @ConditionalOnMissingBean + public TenantConfigurationManagement tenantConfigurationManagement() { + return new JpaTenantConfigurationManagement(); + } + + /** + * {@link JpaTenantConfigurationManagement} bean. + * + * @return a new {@link TenantConfigurationManagement} + */ + @Bean + @ConditionalOnMissingBean + public TargetManagement targetManagement() { + return new JpaTargetManagement(); + } + + /** + * {@link JpaTargetFilterQueryManagement} bean. + * + * @return a new {@link TargetFilterQueryManagement} + */ + @Bean + @ConditionalOnMissingBean + public TargetFilterQueryManagement targetFilterQueryManagement() { + return new JpaTargetFilterQueryManagement(); + } + + /** + * {@link JpaTagManagement} bean. + * + * @return a new {@link TagManagement} + */ + @Bean + @ConditionalOnMissingBean + public TagManagement tagManagement() { + return new JpaTagManagement(); + } + + /** + * {@link JpaSoftwareManagement} bean. + * + * @return a new {@link SoftwareManagement} + */ + @Bean + @ConditionalOnMissingBean + public SoftwareManagement softwareManagement() { + return new JpaSoftwareManagement(); + } + + /** + * {@link JpaRolloutManagement} bean. + * + * @return a new {@link RolloutManagement} + */ + @Bean + @ConditionalOnMissingBean + public RolloutManagement rolloutManagement() { + return new JpaRolloutManagement(); + } + + /** + * {@link JpaRolloutGroupManagement} bean. + * + * @return a new {@link RolloutGroupManagement} + */ + @Bean + @ConditionalOnMissingBean + public RolloutGroupManagement rolloutGroupManagement() { + return new JpaRolloutGroupManagement(); + } + + /** + * {@link JpaDeploymentManagement} bean. + * + * @return a new {@link DeploymentManagement} + */ + @Bean + @ConditionalOnMissingBean + public DeploymentManagement deploymentManagement() { + return new JpaDeploymentManagement(); + } + + /** + * {@link JpaControllerManagement} bean. + * + * @return a new {@link ControllerManagement} + */ + @Bean + @ConditionalOnMissingBean + public ControllerManagement controllerManagement() { + return new JpaControllerManagement(); + } + + /** + * {@link JpaArtifactManagement} bean. + * + * @return a new {@link ArtifactManagement} + */ + + @Bean + @ConditionalOnMissingBean + public ArtifactManagement artifactManagement() { + return new JpaArtifactManagement(); + } + + /** + * {@link JpaEntityFactory} bean. + * + * @return a new {@link EntityFactory} + */ + @Bean + @ConditionalOnMissingBean + public EntityFactory entityFactory() { + return new JpaEntityFactory(); + } +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ActionRepository.java similarity index 79% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ActionRepository.java index 742a7d731..0eebbced1 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ActionRepository.java @@ -6,11 +6,17 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.Collection; import java.util.List; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; +import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.DistributionSet; @@ -37,7 +43,7 @@ import org.springframework.transaction.annotation.Transactional; * */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -public interface ActionRepository extends BaseEntityRepository, JpaSpecificationExecutor { +public interface ActionRepository extends BaseEntityRepository, JpaSpecificationExecutor { /** * Retrieves an Action with all lazy attributes. * @@ -46,7 +52,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * @return the found {@link Action} */ @EntityGraph(value = "Action.all", type = EntityGraphType.LOAD) - Action findById(Long actionId); + JpaAction findById(Long actionId); /** * Retrieves all {@link Action}s which are referring the given @@ -58,7 +64,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * the {@link DistributionSet} on which will be filtered * @return the found {@link Action}s */ - Page findByDistributionSet(final Pageable pageable, final DistributionSet ds); + Page findByDistributionSet(final Pageable pageable, final JpaDistributionSet ds); /** * Retrieves all {@link Action}s which are referring the given @@ -70,7 +76,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * the target to find assigned actions * @return the found {@link Action}s */ - Slice findByTarget(Pageable pageable, Target target); + Slice findByTarget(Pageable pageable, JpaTarget target); /** * Retrieves all {@link Action}s which are active and referring the given @@ -86,7 +92,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * @return the found {@link Action}s */ @EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD) - List findByTargetAndActiveOrderByIdAsc(final Target target, boolean active); + List findByTargetAndActiveOrderByIdAsc(final JpaTarget target, boolean active); /** * Retrieves latest {@link UpdateAction} for given target and @@ -99,9 +105,9 @@ public interface ActionRepository extends BaseEntityRepository, Jp * @return action if there is one with assigned target and module is part of * assigned {@link DistributionSet}. */ - @Query("Select a from Action a join a.distributionSet ds join ds.modules modul where a.target.controllerId = :target and modul = :module order by a.id desc") + @Query("Select a from JpaAction a join a.distributionSet ds join ds.modules modul where a.target.controllerId = :target and modul = :module order by a.id desc") List findActionByTargetAndSoftwareModule(@Param("target") final String targetId, - @Param("module") SoftwareModule module); + @Param("module") JpaSoftwareModule module); /** * Retrieves all {@link UpdateAction}s which are referring the given @@ -115,9 +121,9 @@ public interface ActionRepository extends BaseEntityRepository, Jp * the {@link DistributionSet} on which will be filtered * @return the found {@link UpdateAction}s */ - @Query("Select a from Action a where a.target = :target and a.distributionSet = :ds order by a.id") - Page findByTargetAndDistributionSet(final Pageable pageable, @Param("target") final Target target, - @Param("ds") DistributionSet ds); + @Query("Select a from JpaAction a where a.target = :target and a.distributionSet = :ds order by a.id") + Page findByTargetAndDistributionSet(final Pageable pageable, @Param("target") final JpaTarget target, + @Param("ds") JpaDistributionSet ds); /** * Retrieves all {@link Action}s of a specific target, without pagination @@ -127,8 +133,8 @@ public interface ActionRepository extends BaseEntityRepository, Jp * to search for * @return a list of actions according to the searched target */ - @Query("Select a from Action a where a.target = :target order by a.id") - List findByTarget(@Param("target") final Target target); + @Query("Select a from JpaAction a where a.target = :target order by a.id") + List findByTarget(@Param("target") final JpaTarget target); /** * Retrieves all {@link Action}s of a specific target and given active flag @@ -143,8 +149,8 @@ public interface ActionRepository extends BaseEntityRepository, Jp * {@code false} for inactive * @return a paged list of actions ordered by action ID */ - @Query("Select a from Action a where a.target = :target and a.active= :active order by a.id") - Page findByActiveAndTarget(Pageable pageable, @Param("target") Target target, + @Query("Select a from JpaAction a where a.target = :target and a.active= :active order by a.id") + Page findByActiveAndTarget(Pageable pageable, @Param("target") JpaTarget target, @Param("active") boolean active); /** @@ -160,8 +166,8 @@ public interface ActionRepository extends BaseEntityRepository, Jp * @return a list of actions ordered by action ID */ @EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD) - @Query("Select a from Action a where a.target = :target and a.active= :active order by a.id") - List findByActiveAndTarget(@Param("target") Target target, @Param("active") boolean active); + @Query("Select a from JpaAction a where a.target = :target and a.active= :active order by a.id") + List findByActiveAndTarget(@Param("target") JpaTarget target, @Param("active") boolean active); /** * Updates all {@link Action} to inactive for all targets with given ID. @@ -174,8 +180,8 @@ public interface ActionRepository extends BaseEntityRepository, Jp */ @Modifying @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); + @Query("UPDATE JpaAction a SET a.active = false WHERE a IN :keySet AND a.target IN :targetsIds") + void setToInactive(@Param("keySet") List keySet, @Param("targetsIds") List targetsIds); /** * Switches the status of actions from one specific status into another, @@ -193,7 +199,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp */ @Modifying @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") + @Query("UPDATE JpaAction 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); @@ -213,8 +219,8 @@ public interface ActionRepository extends BaseEntityRepository, Jp */ @Modifying @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, + @Query("UPDATE JpaAction 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") JpaRollout rollout, @Param("active") boolean active, @Param("currentStatus") Action.Status currentStatus); /** @@ -228,8 +234,8 @@ public interface ActionRepository extends BaseEntityRepository, Jp * the status which the actions should not have * @return the found list of {@link Action}s */ - @Query("SELECT a FROM Action a WHERE a.active = true AND a.distributionSet.requiredMigrationStep = false AND a.target IN ?1 AND a.status != ?2") - List findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetRequiredMigrationStep( + @Query("SELECT a FROM JpaAction a WHERE a.active = true AND a.distributionSet.requiredMigrationStep = false AND a.target IN ?1 AND a.status != ?2") + List findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetRequiredMigrationStep( Collection targetIds, Action.Status notStatus); /** @@ -239,15 +245,15 @@ public interface ActionRepository extends BaseEntityRepository, Jp * the target to count the {@link Action}s * @return the count of actions referring to the given target */ - Long countByTarget(Target target); + Long countByTarget(JpaTarget target); @Override @CacheEvict(value = "feedbackReceivedOverTime", allEntries = true) - List save(Iterable entities); + List save(Iterable entities); @Override @CacheEvict(value = "feedbackReceivedOverTime", allEntries = true) - S save(S entity); + S save(S entity); /** * Counts all {@link Action}s referring to the given DistributionSet. @@ -256,7 +262,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * DistributionSet to count the {@link Action}s from * @return the count of actions referring to the given distributionSet */ - Long countByDistributionSet(DistributionSet distributionSet); + Long countByDistributionSet(JpaDistributionSet distributionSet); /** * Counts all {@link Action}s referring to the given rollout. @@ -265,7 +271,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * the rollout to count the {@link Action}s from * @return the count of actions referring to the given rollout */ - Long countByRollout(Rollout rollout); + Long countByRollout(JpaRollout rollout); /** * Counts all actions referring to a given rollout and rolloutgroup which @@ -286,8 +292,8 @@ public interface ActionRepository extends BaseEntityRepository, Jp * @return the count of actions referring the rollout and rolloutgroup and * are not in given states */ - Long countByRolloutAndRolloutGroupAndStatusNotAndStatusNotAndStatusNot(Rollout rollout, RolloutGroup rolloutGroup, - Status notStatus1, Status notStatus2, Status notStatus3); + Long countByRolloutAndRolloutGroupAndStatusNotAndStatusNotAndStatusNot(JpaRollout rollout, + JpaRolloutGroup rolloutGroup, Status notStatus1, Status notStatus2, Status notStatus3); /** * Counts all actions referring to a given rollout and rolloutgroup. @@ -298,7 +304,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * the rolloutgroup the actions belong to * @return the count of actions referring to a rollout and rolloutgroup */ - Long countByRolloutAndRolloutGroup(Rollout rollout, RolloutGroup rolloutGroup); + Long countByRolloutAndRolloutGroup(JpaRollout rollout, JpaRolloutGroup rolloutGroup); /** * Counts all actions referring to a given rollout, rolloutgroup and status. @@ -329,7 +335,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * @return the actions referring a specific rollout and a specific parent * rolloutgroup in a specific status */ - List findByRolloutAndRolloutGroupParentAndStatus(Rollout rollout, RolloutGroup rolloutGroupParent, + List findByRolloutAndRolloutGroupParentAndStatus(JpaRollout rollout, JpaRolloutGroup rolloutGroupParent, Status actionStatus); /** @@ -341,7 +347,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * the status of the actions * @return the actions referring a specific rollout an in a specific status */ - List findByRolloutAndStatus(Rollout rollout, Status actionStatus); + List findByRolloutAndStatus(JpaRollout rollout, Status actionStatus); /** * Get list of objects which has details of status and count of targets in @@ -351,7 +357,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * id of {@link Rollout} * @return list of objects with status and target count */ - @Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus( a.rollout.id, a.status , COUNT(a.target)) FROM Action a WHERE a.rollout.id IN ?1 GROUP BY a.rollout.id,a.status") + @Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus( a.rollout.id, a.status , COUNT(a.target)) FROM JpaAction a WHERE a.rollout.id IN ?1 GROUP BY a.rollout.id,a.status") List getStatusCountByRolloutId(List rolloutId); /** @@ -362,7 +368,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * id of {@link Rollout} * @return list of objects with status and target count */ - @Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus( a.rollout.id, a.status , COUNT(a.target)) FROM Action a WHERE a.rollout.id = ?1 GROUP BY a.rollout.id,a.status") + @Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus( a.rollout.id, a.status , COUNT(a.target)) FROM JpaAction a WHERE a.rollout.id = ?1 GROUP BY a.rollout.id,a.status") List getStatusCountByRolloutId(Long rolloutId); /** @@ -373,7 +379,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * id of {@link RolloutGroup} * @return list of objects with status and target count */ - @Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus(a.rolloutGroup.id, a.status , COUNT(a.target)) FROM Action a WHERE a.rolloutGroup.id = ?1 GROUP BY a.rolloutGroup.id, a.status") + @Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus(a.rolloutGroup.id, a.status , COUNT(a.target)) FROM JpaAction a WHERE a.rolloutGroup.id = ?1 GROUP BY a.rolloutGroup.id, a.status") List getStatusCountByRolloutGroupId(Long rolloutGroupId); /** @@ -384,7 +390,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * list of id of {@link RolloutGroup} * @return list of objects with status and target count */ - @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") + @Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus(a.rolloutGroup.id, a.status , COUNT(a.target)) FROM JpaAction a WHERE a.rolloutGroup.id IN ?1 GROUP BY a.rolloutGroup.id, a.status") List getStatusCountByRolloutGroupId(List rolloutGroupId); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionStatusRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ActionStatusRepository.java similarity index 81% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionStatusRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ActionStatusRepository.java index 2a0e8cfb3..7a2c574df 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionStatusRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ActionStatusRepository.java @@ -6,8 +6,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.ActionStatus; @@ -25,7 +27,7 @@ import org.springframework.transaction.annotation.Transactional; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface ActionStatusRepository - extends BaseEntityRepository, JpaSpecificationExecutor { + extends BaseEntityRepository, JpaSpecificationExecutor { /** * Counts {@link ActionStatus} entries of given {@link Action} in @@ -35,7 +37,7 @@ public interface ActionStatusRepository * to count status entries * @return number of actions in repository */ - Long countByAction(Action action); + Long countByAction(JpaAction action); /** * Counts {@link ActionStatus} entries of given {@link Action} with given @@ -47,7 +49,7 @@ public interface ActionStatusRepository * to filter for * @return number of actions in repository */ - Long countByActionAndStatus(Action action, Status status); + Long countByActionAndStatus(JpaAction action, Status status); /** * Retrieves all {@link ActionStatus} entries from repository of given @@ -59,7 +61,7 @@ public interface ActionStatusRepository * of the status entries * @return pages list of {@link ActionStatus} entries */ - Page findByAction(Pageable pageReq, Action action); + Page findByAction(Pageable pageReq, JpaAction action); /** * Finds all status updates for the defined action and target including @@ -74,6 +76,6 @@ public interface ActionStatusRepository * @return Page with found targets */ @EntityGraph(value = "ActionStatus.withMessages", type = EntityGraphType.LOAD) - Page getByAction(Pageable pageReq, Action action); + Page getByAction(Pageable pageReq, JpaAction action); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/BaseEntityRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/BaseEntityRepository.java similarity index 85% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/BaseEntityRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/BaseEntityRepository.java index 16f80596d..0d9f72b37 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/BaseEntityRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/BaseEntityRepository.java @@ -6,10 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.io.Serializable; +import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTenantAwareBaseEntity; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.repository.NoRepositoryBean; @@ -27,7 +28,7 @@ import org.springframework.transaction.annotation.Transactional; */ @NoRepositoryBean @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -public interface BaseEntityRepository +public interface BaseEntityRepository extends PagingAndSortingRepository { /** diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/CurrentTenantCacheKeyGenerator.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/CurrentTenantCacheKeyGenerator.java new file mode 100644 index 000000000..029246d2d --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/CurrentTenantCacheKeyGenerator.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Service; + +/** + * Defines the interfaces to register the {@link KeyGenerator} as bean which is + * used by spring caching framework to resolve the key-generator. The + * key-generator must registered as bean so spring can resolve the key-generator + * by its name. + * + * When using the {@link Service} annotation e.g. by {@link JpaSystemManagement} + * the bean registration must be declared by the interface due spring registers + * the bean by the implemented interfaces. So introduce a single interface for + * the {@link JpaSystemManagement} implementation to allow it to register the + * key-generator bean. + * + */ +@FunctionalInterface +public interface CurrentTenantCacheKeyGenerator { + + /** + * Bean declaration to register a {@code currentTenantKeyGenerator} bean + * which is used by the caching framework. + * + * @return the {@link KeyGenerator} to be used to cache the values of the + * current used tenant in the {@link JpaSystemManagement} + */ + @Bean + KeyGenerator currentTenantKeyGenerator(); +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DeploymentHelper.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DeploymentHelper.java new file mode 100644 index 000000000..f5d00862b --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DeploymentHelper.java @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.repository.TargetManagement; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; + +/** + * Utility class for deployment related topics. + * + */ +public final class DeploymentHelper { + + private DeploymentHelper() { + // utility class + } + + /** + * Internal helper method used only inside service level. As a result is no + * additional security necessary. + * + * @param target + * to update + * @param status + * of the target + * @param setInstalledDate + * to set + * @param entityManager + * for the operation + * @param targetInfoRepository + * for the operation + * + * @return updated target + */ + static JpaTarget updateTargetInfo(@NotNull final JpaTarget target, @NotNull final TargetUpdateStatus status, + final boolean setInstalledDate, final TargetInfoRepository targetInfoRepository, + final EntityManager entityManager) { + final JpaTargetInfo ts = (JpaTargetInfo) target.getTargetInfo(); + ts.setUpdateStatus(status); + + if (setInstalledDate) { + ts.setInstallationDate(System.currentTimeMillis()); + } + targetInfoRepository.save(ts); + return entityManager.merge(target); + } + + /** + * This method is called, when cancellation has been successful. It sets the + * action to canceled, resets the meta data of the target and in case there + * is a new action this action is triggered. + * + * @param action + * the action which is set to canceled + * @param actionRepository + * for the operation + * @param targetManagement + * for the operation + * @param entityManager + * for the operation + * @param targetInfoRepository + * for the operation + */ + static void successCancellation(final JpaAction action, final ActionRepository actionRepository, + final TargetManagement targetManagement, final TargetInfoRepository targetInfoRepository, + final EntityManager entityManager) { + + // set action inactive + action.setActive(false); + action.setStatus(Status.CANCELED); + + final JpaTarget target = (JpaTarget) action.getTarget(); + final List nextActiveActions = actionRepository.findByTargetAndActiveOrderByIdAsc(target, true).stream() + .filter(a -> !a.getId().equals(action.getId())).collect(Collectors.toList()); + + if (nextActiveActions.isEmpty()) { + target.setAssignedDistributionSet(target.getTargetInfo().getInstalledDistributionSet()); + updateTargetInfo(target, TargetUpdateStatus.IN_SYNC, false, targetInfoRepository, entityManager); + } else { + target.setAssignedDistributionSet(nextActiveActions.get(0).getDistributionSet()); + } + targetManagement.updateTarget(target); + } + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetMetadataRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetMetadataRepository.java similarity index 70% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetMetadataRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetMetadataRepository.java index c042a32d0..7b8b1b20f 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetMetadataRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetMetadataRepository.java @@ -6,10 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; +import org.eclipse.hawkbit.repository.jpa.model.DsMetadataCompositeKey; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata; 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; @@ -17,13 +18,10 @@ import org.springframework.transaction.annotation.Transactional; /** * {@link DistributionSetMetadata} repository. - * - * - * */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface DistributionSetMetadataRepository - extends PagingAndSortingRepository, - JpaSpecificationExecutor { + extends PagingAndSortingRepository, + JpaSpecificationExecutor { } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java similarity index 62% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java index f2138bb2d..83791a66d 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java @@ -6,15 +6,19 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.Collection; import java.util.List; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetTag; -import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Tag; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; @@ -27,12 +31,10 @@ import org.springframework.transaction.annotation.Transactional; /** * {@link DistributionSet} repository. * - * - * */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface DistributionSetRepository - extends BaseEntityRepository, JpaSpecificationExecutor { + extends BaseEntityRepository, JpaSpecificationExecutor { /** * Finds {@link DistributionSet}s by assigned {@link Tag}. @@ -41,8 +43,8 @@ public interface DistributionSetRepository * to be found * @return list of found {@link DistributionSet}s */ - @Query(value = "Select Distinct ds from DistributionSet ds join ds.tags dst where dst = :tag") - List findByTag(@Param("tag") final DistributionSetTag tag); + @Query(value = "Select Distinct ds from JpaDistributionSet ds join ds.tags dst where dst = :tag") + List findByTag(@Param("tag") final JpaDistributionSetTag tag); /** * deletes the {@link DistributionSet}s with the given IDs. @@ -52,9 +54,12 @@ public interface DistributionSetRepository */ @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Query("update DistributionSet d set d.deleted = 1 where d.id in :ids") + @Query("update JpaDistributionSet d set d.deleted = 1 where d.id in :ids") void deleteDistributionSet(@Param("ids") Long... ids); + @Override + List findAll(Iterable ids); + /** * deletes {@link DistributionSet}s by the given IDs. * @@ -65,7 +70,7 @@ public interface DistributionSetRepository @Modifying @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") + @Query("DELETE FROM JpaDistributionSet d WHERE d.id IN ?1") int deleteByIdIn(Collection ids); /** @@ -76,18 +81,29 @@ public interface DistributionSetRepository * to search for * @return {@link List} of found {@link DistributionSet}s */ - List findByModules(SoftwareModule module); + List findByModules(JpaSoftwareModule module); /** - * Finds {@link DistributionSet}s based on given ID if they are not assigned - * yet to an {@link UpdateAction}, i.e. unused. + * Finds {@link DistributionSet}s based on given ID that are assigned yet to + * an {@link Action}, i.e. in use. * * @param ids * to search for - * @return + * @return list of {@link DistributionSet#getId()} */ - @Query("select ac.distributionSet.id from Action ac where ac.distributionSet.id in :ids") - List findAssignedDistributionSetsById(@Param("ids") Long... ids); + @Query("select ac.distributionSet.id from JpaAction ac where ac.distributionSet.id in :ids") + List findAssignedToTargetDistributionSetsById(@Param("ids") Long... ids); + + /** + * Finds {@link DistributionSet}s based on given ID that are assigned yet to + * an {@link Rollout}, i.e. in use. + * + * @param ids + * to search for + * @return list of {@link DistributionSet#getId()} + */ + @Query("select ra.distributionSet.id from JpaRollout ra where ra.distributionSet.id in :ids") + List findAssignedToRolloutDistributionSetsById(@Param("ids") Long... ids); /** * Saves all given {@link DistributionSet}s. @@ -100,7 +116,7 @@ public interface DistributionSetRepository * @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable) */ @Override - List save(Iterable entities); + List save(Iterable entities); /** * Finds the distribution set for a specific action. @@ -109,8 +125,8 @@ public interface DistributionSetRepository * the action associated with the distribution set to find * @return the distribution set associated with the given action */ - @Query("select DISTINCT d from DistributionSet d join fetch d.modules m join d.actions a where a = :action") - DistributionSet findByAction(@Param("action") Action action); + @Query("select DISTINCT d from JpaDistributionSet d join fetch d.modules m join d.actions a where a = :action") + JpaDistributionSet findByAction(@Param("action") JpaAction action); /** * Counts {@link DistributionSet} instances of given type in the repository. @@ -119,7 +135,7 @@ public interface DistributionSetRepository * to search for * @return number of found {@link DistributionSet}s */ - long countByType(DistributionSetType type); + long countByType(JpaDistributionSetType type); /** * Counts {@link DistributionSet} with given diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTagRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetTagRepository.java similarity index 79% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTagRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetTagRepository.java index 8521a96b9..d13316b91 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTagRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetTagRepository.java @@ -6,10 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.List; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.TargetTag; @@ -24,7 +25,7 @@ import org.springframework.transaction.annotation.Transactional; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface DistributionSetTagRepository - extends BaseEntityRepository, JpaSpecificationExecutor { + extends BaseEntityRepository, JpaSpecificationExecutor { /** * deletes the {@link DistributionSet} with the given name. * @@ -43,7 +44,7 @@ public interface DistributionSetTagRepository * to filter on * @return the {@link DistributionSetTag} if found, otherwise null */ - DistributionSetTag findByNameEquals(final String tagName); + JpaDistributionSetTag findByNameEquals(final String tagName); /** * Returns all instances of the type. @@ -51,8 +52,8 @@ public interface DistributionSetTagRepository * @return all entities */ @Override - List findAll(); + List findAll(); @Override - List save(Iterable entities); + List save(Iterable entities); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTypeRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetTypeRepository.java similarity index 80% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTypeRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetTypeRepository.java index 289dd6c09..82754d7f8 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTypeRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetTypeRepository.java @@ -6,10 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; import org.eclipse.hawkbit.repository.model.DistributionSetType; -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; @@ -23,7 +24,7 @@ import org.springframework.transaction.annotation.Transactional; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface DistributionSetTypeRepository - extends BaseEntityRepository, JpaSpecificationExecutor { + extends BaseEntityRepository, JpaSpecificationExecutor { /** * @@ -34,7 +35,7 @@ public interface DistributionSetTypeRepository * false if undeleted ones * @return list of found {@link DistributionSetType}s */ - Page findByDeleted(Pageable pageable, boolean isDeleted); + Page findByDeleted(Pageable pageable, boolean isDeleted); /** * @param isDeleted @@ -54,5 +55,5 @@ public interface DistributionSetTypeRepository * @return the number of {@link DistributionSetType}s in the repository * assigned to the given software module type */ - Long countByElementsSmType(SoftwareModuleType softwareModuleType); + Long countByElementsSmType(JpaSoftwareModuleType softwareModuleType); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/EclipseLinkTargetInfoRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/EclipseLinkTargetInfoRepository.java similarity index 85% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/EclipseLinkTargetInfoRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/EclipseLinkTargetInfoRepository.java index e37a51d6c..93b861092 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/EclipseLinkTargetInfoRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/EclipseLinkTargetInfoRepository.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.Collection; import java.util.List; @@ -14,7 +14,7 @@ import java.util.List; import javax.persistence.EntityManager; import javax.persistence.Query; -import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; @@ -40,7 +40,7 @@ public class EclipseLinkTargetInfoRepository implements TargetInfoRepository { @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"); + "update JpaTargetInfo ti set ti.updateStatus = :status where ti.targetId in :targets and ti.updateStatus != :status"); query.setParameter("targets", targets); query.setParameter("status", status); @@ -50,7 +50,7 @@ public class EclipseLinkTargetInfoRepository implements TargetInfoRepository { @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) @CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true) - public S save(final S entity) { + public S save(final S entity) { if (entity.isNew()) { entityManager.persist(entity); @@ -66,7 +66,7 @@ public class EclipseLinkTargetInfoRepository implements TargetInfoRepository { @CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true) public void deleteByTargetIdIn(final Collection targetIDs) { final javax.persistence.Query query = entityManager - .createQuery("DELETE FROM TargetInfo ti where ti.targetId IN :target"); + .createQuery("DELETE FROM JpaTargetInfo ti where ti.targetId IN :target"); query.setParameter("target", targetIDs); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactProviderRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ExternalArtifactProviderRepository.java similarity index 80% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactProviderRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ExternalArtifactProviderRepository.java index d0802d242..039c4917e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactProviderRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ExternalArtifactProviderRepository.java @@ -6,8 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; +import org.eclipse.hawkbit.repository.jpa.model.JpaExternalArtifactProvider; import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; @@ -17,6 +18,6 @@ import org.springframework.transaction.annotation.Transactional; * */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -public interface ExternalArtifactProviderRepository extends BaseEntityRepository { +public interface ExternalArtifactProviderRepository extends BaseEntityRepository { } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ExternalArtifactRepository.java similarity index 81% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ExternalArtifactRepository.java index d20da8013..5845afbee 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/ExternalArtifactRepository.java @@ -6,8 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; +import org.eclipse.hawkbit.repository.jpa.model.JpaExternalArtifact; import org.eclipse.hawkbit.repository.model.ExternalArtifact; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -19,7 +20,7 @@ import org.springframework.transaction.annotation.Transactional; * */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -public interface ExternalArtifactRepository extends BaseEntityRepository { +public interface ExternalArtifactRepository extends BaseEntityRepository { /** * Searches for external artifact for a base software module. @@ -31,6 +32,6 @@ public interface ExternalArtifactRepository extends BaseEntityRepository */ - Page findBySoftwareModuleId(Pageable pageReq, final Long swId); + Page findBySoftwareModuleId(Pageable pageReq, final Long swId); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaArtifactManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaArtifactManagement.java new file mode 100644 index 000000000..3c94d885b --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaArtifactManagement.java @@ -0,0 +1,299 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import java.io.InputStream; +import java.util.List; + +import org.eclipse.hawkbit.artifact.repository.ArtifactRepository; +import org.eclipse.hawkbit.artifact.repository.ArtifactStoreException; +import org.eclipse.hawkbit.artifact.repository.HashNotMatchException; +import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; +import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash; +import org.eclipse.hawkbit.repository.ArtifactManagement; +import org.eclipse.hawkbit.repository.exception.ArtifactDeleteFailedException; +import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.GridFSDBFileNotFoundException; +import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException; +import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException; +import org.eclipse.hawkbit.repository.jpa.model.JpaExternalArtifact; +import org.eclipse.hawkbit.repository.jpa.model.JpaExternalArtifactProvider; +import org.eclipse.hawkbit.repository.jpa.model.JpaLocalArtifact; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification; +import org.eclipse.hawkbit.repository.model.Artifact; +import org.eclipse.hawkbit.repository.model.ExternalArtifact; +import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +/** + * JPA based {@link ArtifactManagement} implementation. + * + */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) +@Validated +public class JpaArtifactManagement implements ArtifactManagement { + + private static final Logger LOG = LoggerFactory.getLogger(JpaArtifactManagement.class); + + @Autowired + private LocalArtifactRepository localArtifactRepository; + + @Autowired + private ExternalArtifactRepository externalArtifactRepository; + + @Autowired + private SoftwareModuleRepository softwareModuleRepository; + + @Autowired + private ExternalArtifactProviderRepository externalArtifactProviderRepository; + + @Autowired + private ArtifactRepository artifactRepository; + + private static LocalArtifact checkForExistingArtifact(final String filename, final boolean overrideExisting, + final SoftwareModule softwareModule) { + if (softwareModule.getLocalArtifactByFilename(filename).isPresent()) { + if (overrideExisting) { + LOG.debug("overriding existing artifact with new filename {}", filename); + return softwareModule.getLocalArtifactByFilename(filename).get(); + } else { + throw new EntityAlreadyExistsException("File with that name already exists in the Software Module"); + } + } + return null; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public ExternalArtifact createExternalArtifact(final ExternalArtifactProvider externalRepository, + final String urlSuffix, final Long moduleId) { + + final SoftwareModule module = getModuleAndThrowExceptionIfThatFails(moduleId); + return externalArtifactRepository.save(new JpaExternalArtifact(externalRepository, urlSuffix, module)); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public ExternalArtifactProvider createExternalArtifactProvider(final String name, final String description, + final String basePath, final String defaultUrlSuffix) { + return externalArtifactProviderRepository + .save(new JpaExternalArtifactProvider(name, description, basePath, defaultUrlSuffix)); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public LocalArtifact createLocalArtifact(final InputStream stream, final Long moduleId, final String filename, + final String providedMd5Sum, final String providedSha1Sum, final boolean overrideExisting, + final String contentType) { + DbArtifact result = null; + + final SoftwareModule softwareModule = getModuleAndThrowExceptionIfThatFails(moduleId); + + final LocalArtifact existing = checkForExistingArtifact(filename, overrideExisting, softwareModule); + + try { + result = artifactRepository.store(stream, filename, contentType, + new DbArtifactHash(providedSha1Sum, providedMd5Sum)); + } catch (final ArtifactStoreException e) { + throw new ArtifactUploadFailedException(e); + } catch (final HashNotMatchException e) { + if (e.getHashFunction().equals(HashNotMatchException.SHA1)) { + throw new InvalidSHA1HashException(e.getMessage(), e); + } else { + throw new InvalidMD5HashException(e.getMessage(), e); + } + } + if (result == null) { + return null; + } + + return storeArtifactMetadata(softwareModule, filename, result, existing); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteExternalArtifact(final Long id) { + final ExternalArtifact existing = externalArtifactRepository.findOne(id); + + if (null == existing) { + return; + } + + existing.getSoftwareModule().removeArtifact(existing); + softwareModuleRepository.save((JpaSoftwareModule) existing.getSoftwareModule()); + externalArtifactRepository.delete(id); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteLocalArtifact(final LocalArtifact existing) { + if (existing == null) { + return; + } + + boolean artifactIsOnlyUsedByOneSoftwareModule = true; + for (final LocalArtifact lArtifact : localArtifactRepository + .findByGridFsFileName(((JpaLocalArtifact) existing).getGridFsFileName())) { + if (!lArtifact.getSoftwareModule().isDeleted() + && Long.compare(lArtifact.getSoftwareModule().getId(), existing.getSoftwareModule().getId()) != 0) { + artifactIsOnlyUsedByOneSoftwareModule = false; + break; + } + } + + if (artifactIsOnlyUsedByOneSoftwareModule) { + try { + LOG.debug("deleting artifact from repository {}", ((JpaLocalArtifact) existing).getGridFsFileName()); + artifactRepository.deleteBySha1(((JpaLocalArtifact) existing).getGridFsFileName()); + } catch (final ArtifactStoreException e) { + throw new ArtifactDeleteFailedException(e); + } + } + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteLocalArtifact(final Long id) { + final JpaLocalArtifact existing = localArtifactRepository.findOne(id); + + if (null == existing) { + return; + } + + deleteLocalArtifact(existing); + + existing.getSoftwareModule().removeArtifact(existing); + softwareModuleRepository.save((JpaSoftwareModule) existing.getSoftwareModule()); + localArtifactRepository.delete(id); + } + + @Override + public Artifact findArtifact(final Long id) { + return localArtifactRepository.findOne(id); + } + + @Override + public List findByFilenameAndSoftwareModule(final String filename, final Long softwareModuleId) { + return localArtifactRepository.findByFilenameAndSoftwareModuleId(filename, softwareModuleId); + } + + @Override + public LocalArtifact findFirstLocalArtifactsBySHA1(final String sha1) { + return localArtifactRepository.findFirstByGridFsFileName(sha1); + } + + @Override + public List findLocalArtifactByFilename(final String filename) { + return localArtifactRepository.findByFilename(filename); + } + + @Override + public Page findLocalArtifactBySoftwareModule(final Pageable pageReq, final Long swId) { + return localArtifactRepository.findBySoftwareModuleId(pageReq, swId); + } + + @Override + public SoftwareModule findSoftwareModuleById(final Long id) { + + final Specification spec = SoftwareModuleSpecification.byId(id); + + return softwareModuleRepository.findOne(spec); + } + + @Override + public SoftwareModule findSoftwareModuleWithDetails(final Long id) { + final SoftwareModule result = findSoftwareModuleById(id); + if (result != null) { + result.getArtifacts().size(); + } + + return result; + } + + private SoftwareModule getModuleAndThrowExceptionIfThatFails(final Long moduleId) { + final SoftwareModule softwareModule = findSoftwareModuleWithDetails(moduleId); + + if (softwareModule == null) { + LOG.debug("no software module with ID {} exists", moduleId); + throw new EntityNotFoundException("Software Module: " + moduleId); + } + return softwareModule; + } + + @Override + public DbArtifact loadLocalArtifactBinary(final LocalArtifact artifact) { + final DbArtifact result = artifactRepository + .getArtifactBySha1(((JpaLocalArtifact) artifact).getGridFsFileName()); + if (result == null) { + throw new GridFSDBFileNotFoundException(((JpaLocalArtifact) artifact).getGridFsFileName()); + } + + return result; + } + + private LocalArtifact storeArtifactMetadata(final SoftwareModule softwareModule, final String providedFilename, + final DbArtifact result, final LocalArtifact existing) { + JpaLocalArtifact artifact = (JpaLocalArtifact) existing; + if (existing == null) { + artifact = new JpaLocalArtifact(result.getHashes().getSha1(), providedFilename, softwareModule); + } + artifact.setMd5Hash(result.getHashes().getMd5()); + artifact.setSha1Hash(result.getHashes().getSha1()); + artifact.setSize(result.getSize()); + + LOG.debug("storing new artifact into repository {}", artifact); + return localArtifactRepository.save(artifact); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public LocalArtifact createLocalArtifact(final InputStream inputStream, final Long moduleId, final String filename, + final boolean overrideExisting) { + return createLocalArtifact(inputStream, moduleId, filename, null, null, overrideExisting, null); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public LocalArtifact createLocalArtifact(final InputStream inputStream, final Long moduleId, final String filename, + final boolean overrideExisting, final String contentType) { + return createLocalArtifact(inputStream, moduleId, filename, null, null, overrideExisting, contentType); + } + + @Override + public Long countLocalArtifactsAll() { + return localArtifactRepository.count(); + } + + @Override + public Long countExternalArtifactsAll() { + return externalArtifactRepository.count(); + } +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java new file mode 100644 index 000000000..b574d1452 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -0,0 +1,477 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.repository.ControllerManagement; +import org.eclipse.hawkbit.repository.RepositoryConstants; +import org.eclipse.hawkbit.repository.RepositoryProperties; +import org.eclipse.hawkbit.repository.TargetManagement; +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException; +import org.eclipse.hawkbit.repository.exception.ToManyStatusEntriesException; +import org.eclipse.hawkbit.repository.jpa.cache.CacheWriteNotify; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus_; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; +import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.repository.model.TenantConfiguration; +import org.eclipse.hawkbit.security.HawkbitSecurityProperties; +import org.eclipse.hawkbit.security.SystemSecurityContext; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +/** + * JPA based {@link ControllerManagement} implementation. + * + */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) +@Validated +public class JpaControllerManagement implements ControllerManagement { + private static final Logger LOG = LoggerFactory.getLogger(ControllerManagement.class); + private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos"); + + @Autowired + private EntityManager entityManager; + + @Autowired + private ActionRepository actionRepository; + + @Autowired + private TargetRepository targetRepository; + + @Autowired + private TargetManagement targetManagement; + + @Autowired + private TargetInfoRepository targetInfoRepository; + + @Autowired + private SoftwareModuleRepository softwareModuleRepository; + + @Autowired + private ActionStatusRepository actionStatusRepository; + + @Autowired + private HawkbitSecurityProperties securityProperties; + + @Autowired + private RepositoryProperties repositoryProperties; + + @Autowired + private TenantConfigurationRepository tenantConfigurationRepository; + + @Autowired + private TenantConfigurationManagement tenantConfigurationManagement; + + @Autowired + private CacheWriteNotify cacheWriteNotify; + + @Autowired + private SystemSecurityContext systemSecurityContext; + + @Override + public String getPollingTime() { + final TenantConfigurationKey configurationKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; + final Class propertyType = String.class; + JpaTenantConfigurationManagement.validateTenantConfigurationDataType(configurationKey, propertyType); + final TenantConfiguration tenantConfiguration = tenantConfigurationRepository + .findByKey(configurationKey.getKeyName()); + + return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement + .buildTenantConfigurationValueByKey(configurationKey, propertyType, tenantConfiguration).getValue()); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public Target updateLastTargetQuery(final String controllerId, final URI address) { + final Target target = targetRepository.findByControllerId(controllerId); + if (target == null) { + throw new EntityNotFoundException(controllerId); + } + + return updateLastTargetQuery(target.getTargetInfo(), address).getTarget(); + } + + @Override + public Action getActionForDownloadByTargetAndSoftwareModule(final String controllerId, + final SoftwareModule module) { + final List action = actionRepository.findActionByTargetAndSoftwareModule(controllerId, + (JpaSoftwareModule) module); + + if (action.isEmpty() || action.get(0).isCancelingOrCanceled()) { + throw new EntityNotFoundException( + "No assigment found for module " + module.getId() + " to target " + controllerId); + } + + return action.get(0); + } + + @Override + public boolean hasTargetArtifactAssigned(final String controllerId, final LocalArtifact localArtifact) { + final Target target = targetRepository.findByControllerId(controllerId); + if (target == null) { + return false; + } + return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(target, localArtifact)) > 0; + } + + @Override + public List findActionByTargetAndActive(final Target target) { + return actionRepository.findByTargetAndActiveOrderByIdAsc((JpaTarget) target, true); + } + + @Override + public List findSoftwareModulesByDistributionSet(final DistributionSet distributionSet) { + return new ArrayList<>(softwareModuleRepository.findByAssignedTo((JpaDistributionSet) distributionSet)); + } + + @Override + public Action findActionWithDetails(final Long actionId) { + return actionRepository.findById(actionId); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public Target findOrRegisterTargetIfItDoesNotexist(final String controllerId, final URI address) { + final Specification spec = (targetRoot, query, cb) -> cb + .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); + + JpaTarget target = targetRepository.findOne(spec); + + if (target == null) { + target = new JpaTarget(controllerId); + target.setDescription("Plug and Play target: " + controllerId); + target.setName(controllerId); + return targetManagement.createTarget(target, TargetUpdateStatus.REGISTERED, System.currentTimeMillis(), + address); + } + + return updateLastTargetQuery(target.getTargetInfo(), address).getTarget(); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public TargetInfo updateTargetStatus(final TargetInfo targetInfo, final TargetUpdateStatus status, + final Long lastTargetQuery, final URI address) { + final JpaTargetInfo mtargetInfo = (JpaTargetInfo) entityManager.merge(targetInfo); + if (status != null) { + mtargetInfo.setUpdateStatus(status); + } + if (lastTargetQuery != null) { + mtargetInfo.setLastTargetQuery(lastTargetQuery); + } + if (address != null) { + mtargetInfo.setAddress(address.toString()); + } + return targetInfoRepository.save(mtargetInfo); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public Action addCancelActionStatus(final ActionStatus actionStatus) { + final JpaAction action = (JpaAction) actionStatus.getAction(); + + checkForToManyStatusEntries(action); + action.setStatus(actionStatus.getStatus()); + + switch (actionStatus.getStatus()) { + case WARNING: + case ERROR: + case RUNNING: + break; + case CANCELED: + case FINISHED: + handleFinishedCancelation(actionStatus, action); + break; + case RETRIEVED: + actionStatus.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Cancellation request retrieved."); + break; + default: + // do nothing + } + actionRepository.save(action); + actionStatusRepository.save((JpaActionStatus) actionStatus); + + return action; + } + + private void handleFinishedCancelation(final ActionStatus actionStatus, final JpaAction action) { + // in case of successful cancellation we also report the success at + // the canceled action itself. + actionStatus.addMessage( + RepositoryConstants.SERVER_MESSAGE_PREFIX + "Cancellation completion is finished sucessfully."); + DeploymentHelper.successCancellation(action, actionRepository, targetManagement, targetInfoRepository, + entityManager); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public Action addUpdateActionStatus(@NotNull final ActionStatus actionStatus) { + final JpaAction action = (JpaAction) actionStatus.getAction(); + + // if action is already closed we accept further status updates if + // permitted so by configuration. This is especially useful if the + // action status feedback channel order from the device cannot be + // guaranteed. However, if an action is closed we do not accept further + // close messages. + if (actionIsNotActiveButIntermediateFeedbackStillAllowed(actionStatus, action)) { + LOG.debug("Update of actionStatus {} for action {} not possible since action not active anymore.", + actionStatus.getId(), action.getId()); + return action; + } + return handleAddUpdateActionStatus((JpaActionStatus) actionStatus, action); + } + + private boolean actionIsNotActiveButIntermediateFeedbackStillAllowed(final ActionStatus actionStatus, + final JpaAction action) { + return !action.isActive() && (repositoryProperties.isRejectActionStatusForClosedAction() + || (Status.ERROR.equals(actionStatus.getStatus()) || Status.FINISHED.equals(actionStatus.getStatus()))); + } + + /** + * Sets {@link TargetUpdateStatus} based on given {@link ActionStatus}. + * + * @param actionStatus + * @param action + * @return + */ + private Action handleAddUpdateActionStatus(final JpaActionStatus actionStatus, final JpaAction action) { + LOG.debug("addUpdateActionStatus for action {}", action.getId()); + + final JpaAction mergedAction = entityManager.merge(action); + JpaTarget mergedTarget = (JpaTarget) mergedAction.getTarget(); + // check for a potential DOS attack + checkForToManyStatusEntries(action); + + switch (actionStatus.getStatus()) { + case ERROR: + mergedTarget = DeploymentHelper.updateTargetInfo(mergedTarget, TargetUpdateStatus.ERROR, false, + targetInfoRepository, entityManager); + handleErrorOnAction(mergedAction, mergedTarget); + break; + case FINISHED: + handleFinishedAndStoreInTargetStatus(mergedTarget, mergedAction); + break; + case CANCELED: + case WARNING: + case RUNNING: + handleIntermediateFeedback(mergedAction, mergedTarget); + break; + default: + break; + } + + actionStatusRepository.save(actionStatus); + + LOG.debug("addUpdateActionStatus {} for target {} is finished.", action.getId(), mergedTarget.getId()); + + return actionRepository.save(mergedAction); + } + + private void handleIntermediateFeedback(final JpaAction mergedAction, final JpaTarget mergedTarget) { + // we change the target state only if the action is still running + // otherwise this is considered as late feedback that does not have + // an impact on the state anymore. + if (mergedAction.isActive()) { + DeploymentHelper.updateTargetInfo(mergedTarget, TargetUpdateStatus.PENDING, false, targetInfoRepository, + entityManager); + } + } + + private void handleErrorOnAction(final JpaAction mergedAction, final JpaTarget mergedTarget) { + mergedAction.setActive(false); + mergedAction.setStatus(Status.ERROR); + mergedTarget.setAssignedDistributionSet(null); + targetManagement.updateTarget(mergedTarget); + } + + private void checkForToManyStatusEntries(final JpaAction action) { + if (securityProperties.getDos().getMaxStatusEntriesPerAction() > 0) { + + final Long statusCount = actionStatusRepository.countByAction(action); + + if (statusCount >= securityProperties.getDos().getMaxStatusEntriesPerAction()) { + LOG_DOS.error( + "Potential denial of service (DOS) attack identfied. More status entries in the system than permitted ({})!", + securityProperties.getDos().getMaxStatusEntriesPerAction()); + throw new ToManyStatusEntriesException( + String.valueOf(securityProperties.getDos().getMaxStatusEntriesPerAction())); + } + } + } + + private void handleFinishedAndStoreInTargetStatus(final JpaTarget target, final JpaAction action) { + action.setActive(false); + action.setStatus(Status.FINISHED); + final JpaTargetInfo targetInfo = (JpaTargetInfo) target.getTargetInfo(); + final JpaDistributionSet ds = (JpaDistributionSet) entityManager.merge(action.getDistributionSet()); + targetInfo.setInstalledDistributionSet(ds); + if (target.getAssignedDistributionSet() != null && targetInfo.getInstalledDistributionSet() != null && target + .getAssignedDistributionSet().getId().equals(targetInfo.getInstalledDistributionSet().getId())) { + targetInfo.setUpdateStatus(TargetUpdateStatus.IN_SYNC); + targetInfo.setInstallationDate(System.currentTimeMillis()); + } else { + targetInfo.setUpdateStatus(TargetUpdateStatus.PENDING); + targetInfo.setInstallationDate(System.currentTimeMillis()); + } + targetInfoRepository.save(targetInfo); + entityManager.detach(ds); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public Target updateControllerAttributes(final String controllerId, final Map data) { + final JpaTarget target = targetRepository.findByControllerId(controllerId); + + if (target == null) { + throw new EntityNotFoundException(controllerId); + } + + final JpaTargetInfo targetInfo = (JpaTargetInfo) target.getTargetInfo(); + targetInfo.getControllerAttributes().putAll(data); + + if (targetInfo.getControllerAttributes().size() > securityProperties.getDos() + .getMaxAttributeEntriesPerTarget()) { + LOG_DOS.info("Target tries to insert more than the allowed number of entries ({}). DOS attack anticipated!", + securityProperties.getDos().getMaxAttributeEntriesPerTarget()); + throw new ToManyAttributeEntriesException( + String.valueOf(securityProperties.getDos().getMaxAttributeEntriesPerTarget())); + } + + targetInfo.setLastTargetQuery(System.currentTimeMillis()); + targetInfo.setRequestControllerAttributes(false); + return targetRepository.save(target); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public Action registerRetrieved(final Action action, final String message) { + return handleRegisterRetrieved((JpaAction) action, message); + } + + /** + * Registers retrieved status for given {@link Target} and {@link Action} if + * it does not exist yet. + * + * @param action + * to the handle status for + * @param message + * for the status + * @return the updated action in case the status has been changed to + * {@link Status#RETRIEVED} + */ + private Action handleRegisterRetrieved(final JpaAction action, final String message) { + // do a manual query with CriteriaBuilder to avoid unnecessary field + // queries and an extra + // count query made by spring-data when using pageable requests, we + // don't need an extra count + // query, we just want to check if the last action status is a retrieved + // or not. + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery queryActionStatus = cb.createQuery(Object[].class); + final Root actionStatusRoot = queryActionStatus.from(JpaActionStatus.class); + final CriteriaQuery query = queryActionStatus + .multiselect(actionStatusRoot.get(JpaActionStatus_.id), actionStatusRoot.get(JpaActionStatus_.status)) + .where(cb.equal(actionStatusRoot.get(JpaActionStatus_.action), action)) + .orderBy(cb.desc(actionStatusRoot.get(JpaActionStatus_.id))); + final List resultList = entityManager.createQuery(query).setFirstResult(0).setMaxResults(1) + .getResultList(); + + // if the latest status is not in retrieve state then we add a retrieved + // state again, we want + // to document a deployment retrieved status and a cancel retrieved + // status, but multiple + // retrieves after the other we don't want to store to protect to + // overflood action status in + // case controller retrieves a action multiple times. + if (resultList.isEmpty() || !Status.RETRIEVED.equals(resultList.get(0)[1])) { + // document that the status has been retrieved + actionStatusRepository + .save(new JpaActionStatus(action, Status.RETRIEVED, System.currentTimeMillis(), message)); + + // don't change the action status itself in case the action is in + // canceling state otherwise + // we modify the action status and the controller won't get the + // cancel job anymore. + if (!action.isCancelingOrCanceled()) { + final JpaAction actionMerge = entityManager.merge(action); + actionMerge.setStatus(Status.RETRIEVED); + return actionRepository.save(actionMerge); + } + } + return action; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public ActionStatus addInformationalActionStatus(final ActionStatus statusMessage) { + return actionStatusRepository.save((JpaActionStatus) statusMessage); + } + + @Override + public String getSecurityTokenByControllerId(final String controllerId) { + final Target target = targetRepository.findByControllerId(controllerId); + return target != null ? target.getSecurityToken() : null; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public TargetInfo updateLastTargetQuery(final TargetInfo target, final URI address) { + return updateTargetStatus(target, null, System.currentTimeMillis(), address); + } + + @Override + public void downloadProgress(final Long statusId, final Long requestedBytes, final Long shippedBytesSinceLast, + final Long shippedBytesOverall) { + cacheWriteNotify.downloadProgress(statusId, requestedBytes, shippedBytesSinceLast, shippedBytesOverall); + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java new file mode 100644 index 000000000..6236e8d6f --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java @@ -0,0 +1,713 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.ListJoin; +import javax.persistence.criteria.Root; +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent; +import org.eclipse.hawkbit.repository.ActionFields; +import org.eclipse.hawkbit.repository.DeploymentManagement; +import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult; +import org.eclipse.hawkbit.repository.TargetManagement; +import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; +import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException; +import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException; +import org.eclipse.hawkbit.repository.jpa.configuration.Constants; +import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionWithStatusCount; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction_; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; +import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout_; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; +import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.Action.ActionType; +import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.ActionWithStatusCount; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.repository.model.TargetWithActionType; +import org.eclipse.hawkbit.security.SystemSecurityContext; +import org.hibernate.validator.constraints.NotEmpty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.data.domain.AuditorAware; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.Modifying; +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.collect.Lists; +import com.google.common.eventbus.EventBus; + +/** + * JPA implementation for {@link DeploymentManagement}. + * + */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) +@Validated +public class JpaDeploymentManagement implements DeploymentManagement { + private static final Logger LOG = LoggerFactory.getLogger(JpaDeploymentManagement.class); + + @Autowired + private EntityManager entityManager; + + @Autowired + private ActionRepository actionRepository; + + @Autowired + private DistributionSetRepository distributoinSetRepository; + + @Autowired + private SoftwareModuleRepository softwareModuleRepository; + + @Autowired + private TargetRepository targetRepository; + + @Autowired + private ActionStatusRepository actionStatusRepository; + + @Autowired + private TargetManagement targetManagement; + + @Autowired + private TargetInfoRepository targetInfoRepository; + + @Autowired + private AuditorAware auditorProvider; + + @Autowired + private EventBus eventBus; + + @Autowired + private AfterTransactionCommitExecutor afterCommit; + + @Autowired + private SystemSecurityContext systemSecurityContext; + + @Override + @Transactional(isolation = Isolation.READ_COMMITTED) + @Modifying + @CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true) + public DistributionSetAssignmentResult assignDistributionSet(final DistributionSet pset, + final List targets) { + + return assignDistributionSetByTargetId((JpaDistributionSet) pset, + targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()), + ActionType.FORCED, org.eclipse.hawkbit.repository.model.RepositoryModelConstants.NO_FORCE_TIME); + + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_COMMITTED) + @CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true) + public DistributionSetAssignmentResult assignDistributionSet(final Long dsID, final String... targetIDs) { + return assignDistributionSet(dsID, ActionType.FORCED, + org.eclipse.hawkbit.repository.model.RepositoryModelConstants.NO_FORCE_TIME, targetIDs); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true) + // Exception squid:S2095: see + // https://jira.sonarsource.com/browse/SONARJAVA-1478 + @SuppressWarnings({ "squid:S2095" }) + public DistributionSetAssignmentResult assignDistributionSet(final Long dsID, final ActionType actionType, + final long forcedTimestamp, final String... targetIDs) { + return assignDistributionSet(dsID, Arrays.stream(targetIDs) + .map(t -> new TargetWithActionType(t, actionType, forcedTimestamp)).collect(Collectors.toList())); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_COMMITTED) + @CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true) + public DistributionSetAssignmentResult assignDistributionSet(final Long dsID, + final Collection targets) { + final JpaDistributionSet set = distributoinSetRepository.findOne(dsID); + if (set == null) { + throw new EntityNotFoundException( + String.format("no %s with id %d found", DistributionSet.class.getSimpleName(), dsID)); + } + + return assignDistributionSetToTargets(set, targets, null, null); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_COMMITTED) + @CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true) + public DistributionSetAssignmentResult assignDistributionSet(final Long dsID, + final Collection targets, final Rollout rollout, final RolloutGroup rolloutGroup) { + final JpaDistributionSet set = distributoinSetRepository.findOne(dsID); + if (set == null) { + throw new EntityNotFoundException( + String.format("no %s with id %d found", DistributionSet.class.getSimpleName(), dsID)); + } + + return assignDistributionSetToTargets(set, targets, (JpaRollout) rollout, (JpaRolloutGroup) rolloutGroup); + } + + /** + * method assigns the {@link DistributionSet} to all {@link Target}s by + * their IDs with a specific {@link ActionType} and {@code forcetime}. + * + * @param dsID + * the ID of the distribution set to assign + * @param targets + * a list of all targets and their action type + * @param rollout + * the rollout for this assignment + * @param rolloutGroup + * the rollout group for this assignment + * @return the assignment result + * + * @throw IncompleteDistributionSetException if mandatory + * {@link SoftwareModuleType} are not assigned as define by the + * {@link DistributionSetType}. + */ + private DistributionSetAssignmentResult assignDistributionSetToTargets(@NotNull final JpaDistributionSet set, + final Collection targetsWithActionType, final JpaRollout rollout, + final JpaRolloutGroup rolloutGroup) { + + if (!set.isComplete()) { + throw new IncompleteDistributionSetException( + "Distribution set of type " + set.getType().getKey() + " is incomplete: " + set.getId()); + } + + final List controllerIDs = targetsWithActionType.stream().map(TargetWithActionType::getTargetId) + .collect(Collectors.toList()); + + LOG.debug("assignDistribution({}) to {} targets", set, controllerIDs.size()); + + final Map targetsWithActionMap = targetsWithActionType.stream() + .collect(Collectors.toMap(TargetWithActionType::getTargetId, Function.identity())); + + // split tIDs length into max entries in-statement because many database + // have constraint of max entries in in-statements e.g. Oracle with + // maximum 1000 elements, so we need to split the entries here and + // execute multiple statements we take the target only into account if + // the requested operation is no duplicate of a previous one + final List targets = Lists.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT).stream() + .map(ids -> targetRepository + .findAll(TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, set.getId()))) + .flatMap(t -> t.stream()).collect(Collectors.toList()); + + if (targets.isEmpty()) { + // detaching as it is not necessary to persist the set itself + entityManager.detach(set); + // return with nothing as all targets had the DS already assigned + return new DistributionSetAssignmentResult(Collections.emptyList(), 0, targetsWithActionType.size(), + Collections.emptyList(), targetManagement); + } + + final List> targetIds = Lists.partition( + targets.stream().map(Target::getId).collect(Collectors.toList()), Constants.MAX_ENTRIES_IN_STATEMENT); + + // override all active actions and set them into canceling state, we + // need to remember which one we have been switched to canceling state + // because for targets which we have changed to canceling we don't want + // to publish the new action update event. + final Set targetIdsCancellList = new HashSet<>(); + targetIds.forEach(ids -> targetIdsCancellList.addAll(overrideObsoleteUpdateActions(ids))); + + // cancel all scheduled actions which are in-active, these actions were + // not active before and the manual assignment which has been done + // cancels the + targetIds.forEach(tIds -> actionRepository.switchStatus(Status.CANCELED, tIds, false, Status.SCHEDULED)); + + // set assigned distribution set and TargetUpdateStatus + final String currentUser; + if (auditorProvider != null) { + currentUser = auditorProvider.getCurrentAuditor(); + } else { + currentUser = null; + } + + targetIds.forEach(tIds -> targetRepository.setAssignedDistributionSet(set, System.currentTimeMillis(), + currentUser, tIds)); + targetIds.forEach(tIds -> targetInfoRepository.setTargetUpdateStatus(TargetUpdateStatus.PENDING, tIds)); + final Map targetIdsToActions = actionRepository + .save(targets.stream().map(t -> createTargetAction(targetsWithActionMap, t, set, rollout, rolloutGroup)) + .collect(Collectors.toList())) + .stream().collect(Collectors.toMap(a -> a.getTarget().getControllerId(), Function.identity())); + + // create initial action status when action is created so we remember + // the initial running status because we will change the status + // of the action itself and with this action status we have a nicer + // action history. + targetIdsToActions.values().forEach(action -> { + final JpaActionStatus actionStatus = new JpaActionStatus(); + actionStatus.setAction(action); + actionStatus.setOccurredAt(action.getCreatedAt()); + actionStatus.setStatus(Status.RUNNING); + actionStatusRepository.save(actionStatus); + }); + + // flush to get action IDs + entityManager.flush(); + // collect updated target and actions IDs in order to return them + final DistributionSetAssignmentResult result = new DistributionSetAssignmentResult( + targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()), targets.size(), + controllerIDs.size() - targets.size(), + targetIdsToActions.values().stream().map(Action::getId).collect(Collectors.toList()), targetManagement); + + LOG.debug("assignDistribution({}) finished {}", set, result); + + final List softwareModules = softwareModuleRepository.findByAssignedTo(set); + + // detaching as it is not necessary to persist the set itself + entityManager.detach(set); + + sendDistributionSetAssignmentEvent(targets, targetIdsCancellList, targetIdsToActions, softwareModules); + + return result; + } + + private void sendDistributionSetAssignmentEvent(final List targets, final Set targetIdsCancellList, + final Map targetIdsToActions, final List softwareModules) { + targets.stream().filter(t -> !!!targetIdsCancellList.contains(t.getId())) + .forEach(t -> assignDistributionSetEvent(t, targetIdsToActions.get(t.getControllerId()).getId(), + softwareModules)); + } + + private static JpaAction createTargetAction(final Map targetsWithActionMap, + final JpaTarget target, final JpaDistributionSet set, final JpaRollout rollout, + final JpaRolloutGroup rolloutGroup) { + final JpaAction actionForTarget = new JpaAction(); + final TargetWithActionType targetWithActionType = targetsWithActionMap.get(target.getControllerId()); + actionForTarget.setActionType(targetWithActionType.getActionType()); + actionForTarget.setForcedTime(targetWithActionType.getForceTime()); + actionForTarget.setActive(true); + actionForTarget.setStatus(Status.RUNNING); + actionForTarget.setTarget(target); + actionForTarget.setDistributionSet(set); + actionForTarget.setRollout(rollout); + actionForTarget.setRolloutGroup(rolloutGroup); + return actionForTarget; + } + + /** + * Sends the {@link TargetAssignDistributionSetEvent} for a specific target + * to the {@link EventBus}. + * + * @param target + * the Target which has been assigned to a distribution set + * @param actionId + * the action id of the assignment + * @param softwareModules + * the software modules which have been assigned + */ + private void assignDistributionSetEvent(final JpaTarget target, final Long actionId, + final List modules) { + ((JpaTargetInfo) target.getTargetInfo()).setUpdateStatus(TargetUpdateStatus.PENDING); + final String targetSecurityToken = systemSecurityContext.runAsSystem(() -> target.getSecurityToken()); + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Collection softwareModules = (Collection) modules; + afterCommit.afterCommit(() -> { + eventBus.post(new TargetInfoUpdateEvent(target.getTargetInfo())); + eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(), + target.getControllerId(), actionId, softwareModules, target.getTargetInfo().getAddress(), + targetSecurityToken)); + }); + } + + /** + * Removes {@link UpdateAction}s that are no longer necessary and sends + * cancellations to the controller. + * + * @param myTarget + * to override {@link UpdateAction}s + */ + private Set overrideObsoleteUpdateActions(final List targetsIds) { + + final Set cancelledTargetIds = new HashSet<>(); + + // Figure out if there are potential target/action combinations that + // need to be considered + // for cancelation + final List activeActions = actionRepository + .findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetRequiredMigrationStep(targetsIds, + Action.Status.CANCELING); + activeActions.forEach(action -> { + action.setStatus(Status.CANCELING); + // document that the status has been retrieved + + actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(), + "manual cancelation requested")); + + cancelAssignDistributionSetEvent(action.getTarget(), action.getId()); + + cancelledTargetIds.add(action.getTarget().getId()); + }); + + actionRepository.save(activeActions); + + return cancelledTargetIds; + + } + + private DistributionSetAssignmentResult assignDistributionSetByTargetId(@NotNull final JpaDistributionSet set, + @NotEmpty final List tIDs, final ActionType actionType, final long forcedTime) { + + return assignDistributionSetToTargets(set, tIDs.stream() + .map(t -> new TargetWithActionType(t, actionType, forcedTime)).collect(Collectors.toList()), null, + null); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_COMMITTED) + public Action cancelAction(final Action action, final Target target) { + LOG.debug("cancelAction({}, {})", action, target); + if (action.isCancelingOrCanceled()) { + throw new CancelActionNotAllowedException("Actions in canceling or canceled state cannot be canceled"); + } + final JpaAction myAction = (JpaAction) entityManager.merge(action); + + if (myAction.isActive()) { + LOG.debug("action ({}) was still active. Change to {}.", action, Status.CANCELING); + myAction.setStatus(Status.CANCELING); + + // document that the status has been retrieved + actionStatusRepository.save(new JpaActionStatus(myAction, Status.CANCELING, System.currentTimeMillis(), + "manual cancelation requested")); + final Action saveAction = actionRepository.save(myAction); + cancelAssignDistributionSetEvent(target, myAction.getId()); + + return saveAction; + } else { + throw new CancelActionNotAllowedException( + "Action [id: " + action.getId() + "] is not active and cannot be canceled"); + } + } + + /** + * Sends the {@link CancelTargetAssignmentEvent} for a specific target to + * the {@link EventBus}. + * + * @param target + * the Target which has been assigned to a distribution set + * @param actionId + * the action id of the assignment + */ + private void cancelAssignDistributionSetEvent(final Target target, final Long actionId) { + afterCommit.afterCommit(() -> eventBus.post(new CancelTargetAssignmentEvent(target.getOptLockRevision(), + target.getTenant(), target.getControllerId(), actionId, target.getTargetInfo().getAddress()))); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_COMMITTED) + public Action forceQuitAction(final Action action) { + final JpaAction mergedAction = (JpaAction) entityManager.merge(action); + + if (!mergedAction.isCancelingOrCanceled()) { + throw new ForceQuitActionNotAllowedException( + "Action [id: " + action.getId() + "] is not canceled yet and cannot be force quit"); + } + + if (!mergedAction.isActive()) { + throw new ForceQuitActionNotAllowedException( + "Action [id: " + action.getId() + "] is not active and cannot be force quit"); + } + + LOG.warn("action ({}) was still activ and has been force quite.", action); + + // document that the status has been retrieved + actionStatusRepository.save(new JpaActionStatus(mergedAction, Status.CANCELED, System.currentTimeMillis(), + "A force quit has been performed.")); + + DeploymentHelper.successCancellation(mergedAction, actionRepository, targetManagement, targetInfoRepository, + entityManager); + + return actionRepository.save(mergedAction); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_COMMITTED) + public void createScheduledAction(final Collection targets, final DistributionSet distributionSet, + final ActionType actionType, final Long forcedTime, final Rollout rollout, + final RolloutGroup rolloutGroup) { + // cancel all current scheduled actions for this target. E.g. an action + // is already scheduled and a next action is created then cancel the + // current scheduled action to cancel. E.g. a new scheduled action is + // created. + final List targetIds = targets.stream().map(t -> t.getId()).collect(Collectors.toList()); + actionRepository.switchStatus(Action.Status.CANCELED, targetIds, false, Action.Status.SCHEDULED); + targets.forEach(target -> { + final JpaAction action = new JpaAction(); + action.setTarget(target); + action.setActive(false); + action.setDistributionSet(distributionSet); + action.setActionType(actionType); + action.setForcedTime(forcedTime); + action.setStatus(Status.SCHEDULED); + action.setRollout(rollout); + action.setRolloutGroup(rolloutGroup); + actionRepository.save(action); + }); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_COMMITTED) + public Action startScheduledAction(final Action action) { + + final JpaAction mergedAction = (JpaAction) entityManager.merge(action); + final JpaTarget mergedTarget = (JpaTarget) entityManager.merge(action.getTarget()); + + // check if we need to override running update actions + final Set overrideObsoleteUpdateActions = overrideObsoleteUpdateActions( + Collections.singletonList(action.getTarget().getId())); + + final boolean hasDistributionSetAlreadyAssigned = targetRepository + .count(TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot( + Collections.singletonList(mergedTarget.getControllerId()), + action.getDistributionSet().getId())) == 0; + if (hasDistributionSetAlreadyAssigned) { + // the target has already the distribution set assigned, we don't + // need to start the scheduled action, just finished it. + mergedAction.setStatus(Status.FINISHED); + mergedAction.setActive(false); + return actionRepository.save(mergedAction); + } + + mergedAction.setActive(true); + mergedAction.setStatus(Status.RUNNING); + final Action savedAction = actionRepository.save(mergedAction); + + final JpaActionStatus actionStatus = new JpaActionStatus(); + actionStatus.setAction(action); + actionStatus.setOccurredAt(action.getCreatedAt()); + actionStatus.setStatus(Status.RUNNING); + actionStatusRepository.save(actionStatus); + + mergedTarget.setAssignedDistributionSet(action.getDistributionSet()); + final JpaTargetInfo targetInfo = (JpaTargetInfo) mergedTarget.getTargetInfo(); + targetInfo.setUpdateStatus(TargetUpdateStatus.PENDING); + targetRepository.save(mergedTarget); + targetInfoRepository.save(targetInfo); + + // in case we canceled an action before for this target, then don't fire + // assignment event + if (!overrideObsoleteUpdateActions.contains(savedAction.getId())) { + final List softwareModules = softwareModuleRepository + .findByAssignedTo((JpaDistributionSet) action.getDistributionSet()); + // send distribution set assignment event + + assignDistributionSetEvent((JpaTarget) mergedAction.getTarget(), mergedAction.getId(), softwareModules); + } + return savedAction; + } + + @Override + public Action findAction(final Long actionId) { + return actionRepository.findOne(actionId); + } + + @Override + public Action findActionWithDetails(final Long actionId) { + return actionRepository.findById(actionId); + } + + @Override + public Slice findActionsByTarget(final Pageable pageable, final Target target) { + return actionRepository.findByTarget(pageable, (JpaTarget) target); + } + + @Override + public List findActionsByTarget(final Target target) { + return actionRepository.findByTarget((JpaTarget) target); + } + + @Override + public List findActionsWithStatusCountByTargetOrderByIdDesc(final Target target) { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery query = cb.createQuery(JpaActionWithStatusCount.class); + final Root actionRoot = query.from(JpaAction.class); + final ListJoin actionStatusJoin = actionRoot.join(JpaAction_.actionStatus, + JoinType.LEFT); + final Join actionDsJoin = actionRoot.join(JpaAction_.distributionSet); + final Join actionRolloutJoin = actionRoot.join(JpaAction_.rollout, JoinType.LEFT); + + final CriteriaQuery multiselect = query.distinct(true).multiselect( + actionRoot.get(JpaAction_.id), actionRoot.get(JpaAction_.actionType), actionRoot.get(JpaAction_.active), + actionRoot.get(JpaAction_.forcedTime), actionRoot.get(JpaAction_.status), + actionRoot.get(JpaAction_.createdAt), actionRoot.get(JpaAction_.lastModifiedAt), + actionDsJoin.get(JpaDistributionSet_.id), actionDsJoin.get(JpaDistributionSet_.name), + actionDsJoin.get(JpaDistributionSet_.version), cb.count(actionStatusJoin), + actionRolloutJoin.get(JpaRollout_.name)); + multiselect.where(cb.equal(actionRoot.get(JpaAction_.target), target)); + multiselect.orderBy(cb.desc(actionRoot.get(JpaAction_.id))); + multiselect.groupBy(actionRoot.get(JpaAction_.id)); + return new ArrayList<>(entityManager.createQuery(multiselect).getResultList()); + } + + @Override + public Page findActionsByTarget(final String rsqlParam, final Target target, final Pageable pageable) { + final Specification specification = RSQLUtility.parse(rsqlParam, ActionFields.class); + + return convertAcPage(actionRepository.findAll((Specification) (root, query, cb) -> cb + .and(specification.toPredicate(root, query, cb), cb.equal(root.get(JpaAction_.target), target)), + pageable), pageable); + } + + private static Page convertAcPage(final Page findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + public Slice findActionsByTarget(final Target foundTarget, final Pageable pageable) { + return actionRepository.findByTarget(pageable, (JpaTarget) foundTarget); + } + + @Override + public Page findActiveActionsByTarget(final Pageable pageable, final Target target) { + return actionRepository.findByActiveAndTarget(pageable, (JpaTarget) target, true); + } + + @Override + public List findActiveActionsByTarget(final Target target) { + return actionRepository.findByActiveAndTarget((JpaTarget) target, true); + } + + @Override + public List findInActiveActionsByTarget(final Target target) { + return actionRepository.findByActiveAndTarget((JpaTarget) target, false); + } + + @Override + public Page findInActiveActionsByTarget(final Pageable pageable, final Target target) { + return actionRepository.findByActiveAndTarget(pageable, (JpaTarget) target, false); + } + + @Override + public Long countActionsByTarget(final Target target) { + return actionRepository.countByTarget((JpaTarget) target); + } + + @Override + public Long countActionsByTarget(final String rsqlParam, final Target target) { + final Specification spec = RSQLUtility.parse(rsqlParam, ActionFields.class); + + return actionRepository.count((root, query, cb) -> cb.and(spec.toPredicate(root, query, cb), + cb.equal(root.get(JpaAction_.target), target))); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public Action forceTargetAction(final Long actionId) { + final JpaAction action = actionRepository.findOne(actionId); + if (action != null && !action.isForced()) { + action.setActionType(ActionType.FORCED); + return actionRepository.save(action); + } + return action; + } + + @Override + public Page findActionStatusByAction(final Pageable pageReq, final Action action) { + return actionStatusRepository.findByAction(pageReq, (JpaAction) action); + } + + @Override + public Page findActionStatusByActionWithMessages(final Pageable pageReq, final Action action) { + return actionStatusRepository.getByAction(pageReq, (JpaAction) action); + } + + @Override + public List findActionsByRolloutGroupParentAndStatus(final Rollout rollout, + final RolloutGroup rolloutGroupParent, final Action.Status actionStatus) { + return actionRepository.findByRolloutAndRolloutGroupParentAndStatus((JpaRollout) rollout, + (JpaRolloutGroup) rolloutGroupParent, actionStatus); + } + + @Override + public List findActionsByRolloutAndStatus(final Rollout rollout, final Action.Status actionStatus) { + return actionRepository.findByRolloutAndStatus((JpaRollout) rollout, actionStatus); + } + + @Override + public Page findActionStatusAll(final Pageable pageable) { + return convertAcSPage(actionStatusRepository.findAll(pageable), pageable); + } + + private static Page convertAcSPage(final Page findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + public Long countActionStatusAll() { + return actionStatusRepository.count(); + } + + @Override + public Long countActionsAll() { + return actionRepository.count(); + } + + @Override + public Slice findActionsByDistributionSet(final Pageable pageable, final DistributionSet ds) { + return actionRepository.findByDistributionSet(pageable, (JpaDistributionSet) ds); + } + + @Override + public Slice findActionsAll(final Pageable pageable) { + return convertAcPage(actionRepository.findAll(pageable), pageable); + } +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java new file mode 100644 index 000000000..0e97d6ff5 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -0,0 +1,745 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; + +import org.eclipse.hawkbit.repository.DistributionSetFields; +import org.eclipse.hawkbit.repository.DistributionSetManagement; +import org.eclipse.hawkbit.repository.DistributionSetMetadataFields; +import org.eclipse.hawkbit.repository.DistributionSetTypeFields; +import org.eclipse.hawkbit.repository.SystemManagement; +import org.eclipse.hawkbit.repository.TagManagement; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagAssigmentResultEvent; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityLockedException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; +import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; +import org.eclipse.hawkbit.repository.jpa.model.DsMetadataCompositeKey; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata_; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; +import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification; +import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTypeSpecification; +import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetFilter; +import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder; +import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import com.google.common.base.Strings; +import com.google.common.eventbus.EventBus; + +/** + * JPA implementation of {@link DistributionSetManagement}. + * + */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) +@Validated +public class JpaDistributionSetManagement implements DistributionSetManagement { + + @Autowired + private EntityManager entityManager; + + @Autowired + private DistributionSetRepository distributionSetRepository; + + @Autowired + private TagManagement tagManagement; + + @Autowired + private SystemManagement systemManagement; + + @Autowired + private DistributionSetTypeRepository distributionSetTypeRepository; + + @Autowired + private DistributionSetMetadataRepository distributionSetMetadataRepository; + + @Autowired + private ActionRepository actionRepository; + + @Autowired + private EventBus eventBus; + + @Autowired + private AfterTransactionCommitExecutor afterCommit; + + @Override + public DistributionSet findDistributionSetByIdWithDetails(final Long distid) { + return distributionSetRepository.findOne(DistributionSetSpecification.byId(distid)); + } + + @Override + public DistributionSet findDistributionSetById(final Long distid) { + return distributionSetRepository.findOne(distid); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public DistributionSetTagAssignmentResult toggleTagAssignment(final Collection dsIds, final String tagName) { + + final List sets = findDistributionSetListWithDetails(dsIds); + final DistributionSetTag myTag = tagManagement.findDistributionSetTag(tagName); + + DistributionSetTagAssignmentResult result; + final List toBeChangedDSs = new ArrayList<>(); + for (final JpaDistributionSet set : sets) { + if (set.getTags().add(myTag)) { + toBeChangedDSs.add(set); + } + } + + // un-assignment case + if (toBeChangedDSs.isEmpty()) { + for (final JpaDistributionSet set : sets) { + if (set.getTags().remove(myTag)) { + toBeChangedDSs.add(set); + } + } + result = new DistributionSetTagAssignmentResult(dsIds.size() - toBeChangedDSs.size(), 0, + toBeChangedDSs.size(), Collections.emptyList(), + new ArrayList<>(distributionSetRepository.save(toBeChangedDSs)), myTag); + } else { + result = new DistributionSetTagAssignmentResult(dsIds.size() - toBeChangedDSs.size(), toBeChangedDSs.size(), + 0, new ArrayList<>(distributionSetRepository.save(toBeChangedDSs)), Collections.emptyList(), myTag); + } + + final DistributionSetTagAssignmentResult resultAssignment = result; + afterCommit.afterCommit(() -> eventBus.post(new DistributionSetTagAssigmentResultEvent(resultAssignment))); + + // no reason to persist the tag + entityManager.detach(myTag); + return result; + } + + private List findDistributionSetListWithDetails(final Collection distributionIdSet) { + return distributionSetRepository.findAll(DistributionSetSpecification.byIds(distributionIdSet)); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public DistributionSet updateDistributionSet(final DistributionSet ds) { + checkNotNull(ds.getId()); + final DistributionSet persisted = findDistributionSetByIdWithDetails(ds.getId()); + checkDistributionSetSoftwareModulesIsAllowedToModify((JpaDistributionSet) ds, persisted.getModules()); + return distributionSetRepository.save((JpaDistributionSet) ds); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteDistributionSet(final Long... distributionSetIDs) { + final List toHardDelete = new ArrayList<>(); + + final List assigned = distributionSetRepository + .findAssignedToTargetDistributionSetsById(distributionSetIDs); + assigned.addAll(distributionSetRepository.findAssignedToRolloutDistributionSetsById(distributionSetIDs)); + + // soft delete assigned + if (!assigned.isEmpty()) { + distributionSetRepository.deleteDistributionSet(assigned.toArray(new Long[assigned.size()])); + } + + // mark the rest as hard delete + for (final Long setId : distributionSetIDs) { + if (!assigned.contains(setId)) { + toHardDelete.add(setId); + } + } + + // hard delete the rest if exixts + if (!toHardDelete.isEmpty()) { + // don't give the delete statement an empty list, JPA/Oracle cannot + // handle the empty list + distributionSetRepository.deleteByIdIn(toHardDelete); + } + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public DistributionSet createDistributionSet(final DistributionSet dSet) { + prepareDsSave(dSet); + if (dSet.getType() == null) { + dSet.setType(systemManagement.getTenantMetadata().getDefaultDsType()); + } + return distributionSetRepository.save((JpaDistributionSet) dSet); + } + + private void prepareDsSave(final DistributionSet dSet) { + if (dSet.getId() != null) { + throw new EntityAlreadyExistsException("Parameter seems to be an existing, already persisted entity"); + } + + if (distributionSetRepository.countByNameAndVersion(dSet.getName(), dSet.getVersion()) > 0) { + throw new EntityAlreadyExistsException("DistributionSet with that name and version already exists."); + } + + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List createDistributionSets(final Collection distributionSets) { + for (final DistributionSet ds : distributionSets) { + prepareDsSave(ds); + if (ds.getType() == null) { + ds.setType(systemManagement.getTenantMetadata().getDefaultDsType()); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Collection toSave = (Collection) distributionSets; + + return new ArrayList<>(distributionSetRepository.save(toSave)); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public DistributionSet assignSoftwareModules(final DistributionSet ds, final Set softwareModules) { + checkDistributionSetSoftwareModulesIsAllowedToModify((JpaDistributionSet) ds, softwareModules); + for (final SoftwareModule softwareModule : softwareModules) { + ds.addModule(softwareModule); + } + return distributionSetRepository.save((JpaDistributionSet) ds); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public DistributionSet unassignSoftwareModule(final DistributionSet ds, final SoftwareModule softwareModule) { + final Set softwareModules = new HashSet<>(); + softwareModules.add(softwareModule); + ds.removeModule(softwareModule); + checkDistributionSetSoftwareModulesIsAllowedToModify((JpaDistributionSet) ds, softwareModules); + return distributionSetRepository.save((JpaDistributionSet) ds); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public DistributionSetType updateDistributionSetType(final DistributionSetType dsType) { + checkNotNull(dsType.getId()); + + final JpaDistributionSetType persisted = distributionSetTypeRepository.findOne(dsType.getId()); + + // throw exception if user tries to update a DS type that is already in + // use + if (!persisted.areModuleEntriesIdentical(dsType) && distributionSetRepository.countByType(persisted) > 0) { + throw new EntityReadOnlyException( + String.format("distribution set type %s set is already assigned to targets and cannot be changed", + dsType.getName())); + } + + return distributionSetTypeRepository.save((JpaDistributionSetType) dsType); + } + + @Override + public Page findDistributionSetTypesAll(final String rsqlParam, final Pageable pageable) { + final Specification spec = RSQLUtility.parse(rsqlParam, + DistributionSetTypeFields.class); + + return convertDsTPage(distributionSetTypeRepository.findAll(spec, pageable)); + } + + private static Page convertDsTPage(final Page findAll) { + return new PageImpl<>(new ArrayList<>(findAll.getContent())); + } + + @Override + public Page findDistributionSetTypesAll(final Pageable pageable) { + return convertDsTPage(distributionSetTypeRepository.findByDeleted(pageable, false)); + } + + @Override + public Page findDistributionSetsByFilters(final Pageable pageable, + final DistributionSetFilter distributionSetFilter) { + final List> specList = buildDistributionSetSpecifications( + distributionSetFilter); + return convertDsPage(findByCriteriaAPI(pageable, specList), pageable); + } + + private static Page convertDsPage(final Page findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + /** + * + * @param distributionSetFilter + * had details of filters to be applied + * @return a single DistributionSet which is either installed or assigned to + * a specific target or {@code null}. + */ + private DistributionSet findDistributionSetsByFiltersAndInstalledOrAssignedTarget( + final DistributionSetFilter distributionSetFilter) { + final List> specList = buildDistributionSetSpecifications( + distributionSetFilter); + if (specList == null || specList.isEmpty()) { + return null; + } + return distributionSetRepository.findOne(SpecificationsBuilder.combineWithAnd(specList)); + } + + @Override + public Page findDistributionSetsByDeletedAndOrCompleted(final Pageable pageReq, + final Boolean deleted, final Boolean complete) { + final List> specList = new ArrayList<>(); + + if (deleted != null) { + final Specification spec = DistributionSetSpecification.isDeleted(deleted); + specList.add(spec); + } + + if (complete != null) { + final Specification spec = DistributionSetSpecification.isCompleted(complete); + specList.add(spec); + } + + return convertDsPage(findByCriteriaAPI(pageReq, specList), pageReq); + } + + @Override + public Page findDistributionSetsAll(final String rsqlParam, final Pageable pageReq, + final Boolean deleted) { + + final Specification spec = RSQLUtility.parse(rsqlParam, DistributionSetFields.class); + + final List> specList = new ArrayList<>(); + if (deleted != null) { + specList.add(DistributionSetSpecification.isDeleted(deleted)); + } + specList.add(spec); + return convertDsPage(findByCriteriaAPI(pageReq, specList), pageReq); + } + + @Override + public Page findDistributionSetsAllOrderedByLinkTarget(final Pageable pageable, + final DistributionSetFilterBuilder distributionSetFilterBuilder, final String assignedOrInstalled) { + + final DistributionSetFilter filterWithInstalledTargets = distributionSetFilterBuilder + .setInstalledTargetId(assignedOrInstalled).setAssignedTargetId(null).build(); + final DistributionSet installedDS = findDistributionSetsByFiltersAndInstalledOrAssignedTarget( + filterWithInstalledTargets); + + final DistributionSetFilter filterWithAssignedTargets = distributionSetFilterBuilder.setInstalledTargetId(null) + .setAssignedTargetId(assignedOrInstalled).build(); + final DistributionSet assignedDS = findDistributionSetsByFiltersAndInstalledOrAssignedTarget( + filterWithAssignedTargets); + + final DistributionSetFilter dsFilterWithNoTargetLinked = distributionSetFilterBuilder.setInstalledTargetId(null) + .setAssignedTargetId(null).build(); + // first fine the distribution sets filtered by the given filter + // parameters + final Page findDistributionSetsByFilters = findDistributionSetsByFilters(pageable, + dsFilterWithNoTargetLinked); + + final List resultSet = new LinkedList<>(findDistributionSetsByFilters.getContent()); + int orderIndex = 0; + if (installedDS != null) { + final boolean remove = resultSet.remove(installedDS); + if (!remove) { + resultSet.remove(resultSet.size() - 1); + } + resultSet.add(orderIndex, installedDS); + orderIndex++; + } + if (assignedDS != null && !assignedDS.equals(installedDS)) { + final boolean remove = resultSet.remove(assignedDS); + if (!remove) { + resultSet.remove(resultSet.size() - 1); + } + resultSet.add(orderIndex, assignedDS); + } + + return new PageImpl<>(resultSet, pageable, findDistributionSetsByFilters.getTotalElements()); + } + + @Override + public DistributionSet findDistributionSetByNameAndVersion(final String distributionName, final String version) { + final Specification spec = DistributionSetSpecification + .equalsNameAndVersionIgnoreCase(distributionName, version); + return distributionSetRepository.findOne(spec); + + } + + @Override + public List findDistributionSetsAll(final Collection dist) { + return new ArrayList<>(distributionSetRepository.findAll(DistributionSetSpecification.byIds(dist))); + } + + @Override + public Long countDistributionSetsAll() { + + final List> specList = new LinkedList<>(); + + final Specification spec = DistributionSetSpecification.isDeleted(Boolean.FALSE); + specList.add(spec); + + return distributionSetRepository.count(SpecificationsBuilder.combineWithAnd(specList)); + } + + @Override + public Long countDistributionSetTypesAll() { + return distributionSetTypeRepository.countByDeleted(false); + } + + @Override + public DistributionSetType findDistributionSetTypeByName(final String name) { + return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byName(name)); + } + + @Override + public DistributionSetType findDistributionSetTypeById(final Long id) { + return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byId(id)); + } + + @Override + public DistributionSetType findDistributionSetTypeByKey(final String key) { + return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byKey(key)); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public DistributionSetType createDistributionSetType(final DistributionSetType type) { + if (type.getId() != null) { + throw new EntityAlreadyExistsException("Given type contains an Id!"); + } + + return distributionSetTypeRepository.save((JpaDistributionSetType) type); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteDistributionSetType(final DistributionSetType ty) { + final JpaDistributionSetType type = (JpaDistributionSetType) ty; + + if (distributionSetRepository.countByType(type) > 0) { + final JpaDistributionSetType toDelete = entityManager.merge(type); + toDelete.setDeleted(true); + distributionSetTypeRepository.save(toDelete); + } else { + distributionSetTypeRepository.delete(type.getId()); + } + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public DistributionSetMetadata createDistributionSetMetadata(final DistributionSetMetadata md) { + final JpaDistributionSetMetadata metadata = (JpaDistributionSetMetadata) md; + + if (distributionSetMetadataRepository.exists(metadata.getId())) { + throwMetadataKeyAlreadyExists(metadata.getId().getKey()); + } + // merge base distribution set so optLockRevision gets updated and audit + // log written because + // modifying metadata is modifying the base distribution set itself for + // auditing purposes. + entityManager.merge((JpaDistributionSet) metadata.getDistributionSet()).setLastModifiedAt(0L); + return distributionSetMetadataRepository.save(metadata); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public List createDistributionSetMetadata(final Collection md) { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + final Collection metadata = (Collection) md; + + for (final JpaDistributionSetMetadata distributionSetMetadata : metadata) { + checkAndThrowAlreadyIfDistributionSetMetadataExists(distributionSetMetadata.getId()); + } + metadata.forEach(m -> entityManager.merge((JpaDistributionSet) m.getDistributionSet()).setLastModifiedAt(0L)); + + return new ArrayList<>( + (Collection) distributionSetMetadataRepository.save(metadata)); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public DistributionSetMetadata updateDistributionSetMetadata(final DistributionSetMetadata md) { + final JpaDistributionSetMetadata metadata = (JpaDistributionSetMetadata) md; + + // check if exists otherwise throw entity not found exception + findOne(metadata.getDistributionSet(), metadata.getKey()); + // touch it to update the lock revision because we are modifying the + // DS indirectly + entityManager.merge((JpaDistributionSet) metadata.getDistributionSet()).setLastModifiedAt(0L); + return distributionSetMetadataRepository.save(metadata); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public void deleteDistributionSetMetadata(final DistributionSet distributionSet, final String key) { + distributionSetMetadataRepository.delete(new DsMetadataCompositeKey(distributionSet, key)); + } + + @Override + public Page findDistributionSetMetadataByDistributionSetId(final Long distributionSetId, + final Pageable pageable) { + + return convertMdPage(distributionSetMetadataRepository + .findAll((Specification) (root, query, cb) -> cb.equal( + root.get(JpaDistributionSetMetadata_.distributionSet).get(JpaDistributionSet_.id), + distributionSetId), pageable), + pageable); + } + + @Override + public Page findDistributionSetMetadataByDistributionSetId(final Long distributionSetId, + final String rsqlParam, final Pageable pageable) { + + final Specification spec = RSQLUtility.parse(rsqlParam, + DistributionSetMetadataFields.class); + + return convertMdPage( + distributionSetMetadataRepository + .findAll((Specification) (root, query, cb) -> cb.and( + cb.equal(root.get(JpaDistributionSetMetadata_.distributionSet) + .get(JpaDistributionSet_.id), distributionSetId), + spec.toPredicate(root, query, cb)), pageable), + pageable); + } + + private static Page convertMdPage(final Page findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + public DistributionSetMetadata findOne(final DistributionSet distributionSet, final String key) { + final DistributionSetMetadata findOne = distributionSetMetadataRepository + .findOne(new DsMetadataCompositeKey(distributionSet, key)); + if (findOne == null) { + throw new EntityNotFoundException("Metadata with key '" + key + "' does not exist"); + } + return findOne; + } + + @Override + public DistributionSet findDistributionSetByAction(final Action action) { + return distributionSetRepository.findByAction((JpaAction) action); + } + + @Override + public boolean isDistributionSetInUse(final DistributionSet distributionSet) { + return actionRepository.countByDistributionSet((JpaDistributionSet) distributionSet) > 0; + } + + private static List> buildDistributionSetSpecifications( + final DistributionSetFilter distributionSetFilter) { + final List> specList = new ArrayList<>(); + + Specification spec; + + if (null != distributionSetFilter.getIsComplete()) { + spec = DistributionSetSpecification.isCompleted(distributionSetFilter.getIsComplete()); + specList.add(spec); + } + + if (null != distributionSetFilter.getIsDeleted()) { + spec = DistributionSetSpecification.isDeleted(distributionSetFilter.getIsDeleted()); + specList.add(spec); + } + + if (distributionSetFilter.getType() != null) { + spec = DistributionSetSpecification.byType(distributionSetFilter.getType()); + specList.add(spec); + } + + if (!Strings.isNullOrEmpty(distributionSetFilter.getSearchText())) { + spec = DistributionSetSpecification.likeNameOrDescriptionOrVersion(distributionSetFilter.getSearchText()); + specList.add(spec); + } + + if (isDSWithNoTagSelected(distributionSetFilter) || isTagsSelected(distributionSetFilter)) { + spec = DistributionSetSpecification.hasTags(distributionSetFilter.getTagNames(), + distributionSetFilter.getSelectDSWithNoTag()); + specList.add(spec); + } + if (distributionSetFilter.getInstalledTargetId() != null) { + spec = DistributionSetSpecification.installedTarget(distributionSetFilter.getInstalledTargetId()); + specList.add(spec); + } + if (distributionSetFilter.getAssignedTargetId() != null) { + spec = DistributionSetSpecification.assignedTarget(distributionSetFilter.getAssignedTargetId()); + specList.add(spec); + } + return specList; + } + + private void checkDistributionSetSoftwareModulesIsAllowedToModify(final JpaDistributionSet distributionSet, + final Set softwareModules) { + if (!new HashSet(distributionSet.getModules()).equals(softwareModules) + && actionRepository.countByDistributionSet(distributionSet) > 0) { + throw new EntityLockedException( + String.format("distribution set %s:%s is already assigned to targets and cannot be changed", + distributionSet.getName(), distributionSet.getVersion())); + } + } + + private static Boolean isDSWithNoTagSelected(final DistributionSetFilter distributionSetFilter) { + if (distributionSetFilter.getSelectDSWithNoTag() != null && distributionSetFilter.getSelectDSWithNoTag()) { + return true; + } + return false; + } + + private static Boolean isTagsSelected(final DistributionSetFilter distributionSetFilter) { + if (distributionSetFilter.getTagNames() != null && !distributionSetFilter.getTagNames().isEmpty()) { + return true; + } + return false; + } + + /** + * executes findAll with the given {@link DistributionSet} + * {@link Specification}s. + * + * @param pageable + * paging parameter + * @param specList + * list of @link {@link Specification} + * @return the page with the found {@link DistributionSet} + */ + private Page findByCriteriaAPI(final Pageable pageable, + final List> specList) { + + if (specList == null || specList.isEmpty()) { + return distributionSetRepository.findAll(pageable); + } + + return distributionSetRepository.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable); + } + + private void checkAndThrowAlreadyIfDistributionSetMetadataExists(final DsMetadataCompositeKey metadataId) { + if (distributionSetMetadataRepository.exists(metadataId)) { + throw new EntityAlreadyExistsException( + "Metadata entry with key '" + metadataId.getKey() + "' already exists"); + } + } + + private static void throwMetadataKeyAlreadyExists(final String metadataKey) { + throw new EntityAlreadyExistsException("Metadata entry with key '" + metadataKey + "' already exists"); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List assignTag(final Collection dsIds, final DistributionSetTag tag) { + final List allDs = findDistributionSetListWithDetails(dsIds); + + allDs.forEach(ds -> ds.getTags().add(tag)); + + final List save = new ArrayList<>(distributionSetRepository.save(allDs)); + + afterCommit.afterCommit(() -> { + + final DistributionSetTagAssignmentResult result = new DistributionSetTagAssignmentResult(0, save.size(), 0, + save, Collections.emptyList(), tag); + eventBus.post(new DistributionSetTagAssigmentResultEvent(result)); + }); + + return save; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List unAssignAllDistributionSetsByTag(final DistributionSetTag tag) { + + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Collection distributionSets = (Collection) tag.getAssignedToDistributionSet(); + + return new ArrayList<>(unAssignTag(distributionSets, tag)); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public DistributionSet unAssignTag(final Long dsId, final DistributionSetTag distributionSetTag) { + final List allDs = findDistributionSetListWithDetails(Arrays.asList(dsId)); + final List unAssignTag = unAssignTag(allDs, distributionSetTag); + return unAssignTag.isEmpty() ? null : unAssignTag.get(0); + } + + private List unAssignTag(final Collection distributionSets, + final DistributionSetTag tag) { + distributionSets.forEach(ds -> ds.getTags().remove(tag)); + return distributionSetRepository.save(distributionSets); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List createDistributionSetTypes(final Collection types) { + return types.stream().map(this::createDistributionSetType).collect(Collectors.toList()); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteDistributionSet(final DistributionSet set) { + deleteDistributionSet(set.getId()); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public DistributionSetTagAssignmentResult toggleTagAssignment(final Collection sets, + final DistributionSetTag tag) { + return toggleTagAssignment(sets.stream().map(ds -> ds.getId()).collect(Collectors.toList()), tag.getName()); + } + + @Override + public Long countDistributionSetsByType(final DistributionSetType type) { + return distributionSetRepository.countByType((JpaDistributionSetType) type); + } +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaEntityFactory.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaEntityFactory.java new file mode 100644 index 000000000..51b59f08f --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaEntityFactory.java @@ -0,0 +1,215 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import java.util.Collection; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; +import org.eclipse.hawkbit.repository.jpa.model.JpaLocalArtifact; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; +import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetFilterQuery; +import org.eclipse.hawkbit.repository.model.TargetTag; + +/** + * JPA Implementation of {@link EntityFactory}. + * + */ +public class JpaEntityFactory implements EntityFactory { + + @Override + public DistributionSetType generateDistributionSetType() { + return new JpaDistributionSetType(); + } + + @Override + public DistributionSet generateDistributionSet() { + return new JpaDistributionSet(); + } + + @Override + public DistributionSetMetadata generateDistributionSetMetadata() { + return new JpaDistributionSetMetadata(); + } + + @Override + public DistributionSetMetadata generateDistributionSetMetadata(final DistributionSet distributionSet, + final String key, final String value) { + return new JpaDistributionSetMetadata(key, distributionSet, value); + } + + @Override + public DistributionSetType generateDistributionSetType(final String key, final String name, + final String description) { + return new JpaDistributionSetType(key, name, description); + } + + @Override + public DistributionSet generateDistributionSet(final String name, final String version, final String description, + final DistributionSetType type, final Collection moduleList) { + return new JpaDistributionSet(name, version, description, type, moduleList); + } + + @Override + public Target generateTarget(final String controllerId) { + return new JpaTarget(controllerId); + } + + @Override + public Target generateTarget(final String controllerId, final String securityToken) { + if (StringUtils.isEmpty(securityToken)) { + return new JpaTarget(controllerId); + } + return new JpaTarget(controllerId, securityToken); + } + + @Override + public TargetTag generateTargetTag() { + return new JpaTargetTag(); + } + + @Override + public DistributionSetTag generateDistributionSetTag() { + return new JpaDistributionSetTag(); + } + + @Override + public TargetTag generateTargetTag(final String name, final String description, final String colour) { + return new JpaTargetTag(name, description, colour); + } + + @Override + public DistributionSetTag generateDistributionSetTag(final String name, final String description, + final String colour) { + return new JpaDistributionSetTag(name, description, colour); + } + + @Override + public TargetTag generateTargetTag(final String name) { + return new JpaTargetTag(name); + } + + @Override + public DistributionSetTag generateDistributionSetTag(final String name) { + return new JpaDistributionSetTag(name); + } + + @Override + public TargetFilterQuery generateTargetFilterQuery() { + return new JpaTargetFilterQuery(); + } + + @Override + public SoftwareModuleType generateSoftwareModuleType() { + return new JpaSoftwareModuleType(); + } + + @Override + public SoftwareModule generateSoftwareModule() { + return new JpaSoftwareModule(); + } + + @Override + public SoftwareModule generateSoftwareModule(final SoftwareModuleType type, final String name, final String version, + final String description, final String vendor) { + + return new JpaSoftwareModule(type, name, version, description, vendor); + } + + @Override + public SoftwareModuleMetadata generateSoftwareModuleMetadata() { + return new JpaSoftwareModuleMetadata(); + } + + @Override + public SoftwareModuleMetadata generateSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key, + final String value) { + return new JpaSoftwareModuleMetadata(key, softwareModule, value); + } + + @Override + public SoftwareModuleType generateSoftwareModuleType(final String key, final String name, final String description, + final int maxAssignments) { + return new JpaSoftwareModuleType(key, name, description, maxAssignments); + } + + @Override + public Rollout generateRollout() { + return new JpaRollout(); + } + + @Override + public RolloutGroup generateRolloutGroup() { + return new JpaRolloutGroup(); + } + + @Override + public Action generateAction() { + return new JpaAction(); + } + + @Override + public ActionStatus generateActionStatus() { + return new JpaActionStatus(); + } + + @Override + public ActionStatus generateActionStatus(final Action action, final Status status, final Long occurredAt, + final String message) { + return new JpaActionStatus((JpaAction) action, status, occurredAt, message); + } + + @Override + public ActionStatus generateActionStatus(final Action action, final Status status, final Long occurredAt, + final Collection messages) { + + final ActionStatus result = new JpaActionStatus((JpaAction) action, status, occurredAt, null); + messages.forEach(result::addMessage); + + return result; + } + + @Override + public ActionStatus generateActionStatus(final Action action, final Status status, final Long occurredAt) { + return new JpaActionStatus(action, status, occurredAt); + } + + @Override + public LocalArtifact generateLocalArtifact() { + return new JpaLocalArtifact(); + } + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaReportManagement.java similarity index 69% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaReportManagement.java index 326442283..c6795f600 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaReportManagement.java @@ -6,12 +6,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.io.Serializable; -import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.YearMonth; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.ArrayList; @@ -31,35 +29,33 @@ import javax.persistence.criteria.JoinType; import javax.persistence.criteria.ListJoin; import javax.persistence.criteria.Root; -import org.eclipse.hawkbit.report.model.DataReportSeries; -import org.eclipse.hawkbit.report.model.DataReportSeriesItem; -import org.eclipse.hawkbit.report.model.InnerOuterDataReportSeries; -import org.eclipse.hawkbit.report.model.ListReportSeries; -import org.eclipse.hawkbit.report.model.SeriesTime; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSet_; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.hawkbit.repository.model.TargetInfo_; +import org.eclipse.hawkbit.repository.ReportManagement; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.repository.model.Target_; +import org.eclipse.hawkbit.repository.report.model.DataReportSeries; +import org.eclipse.hawkbit.repository.report.model.DataReportSeriesItem; +import org.eclipse.hawkbit.repository.report.model.InnerOuterDataReportSeries; +import org.eclipse.hawkbit.repository.report.model.SeriesTime; import org.eclipse.hawkbit.tenancy.TenantAware; 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 hawkBit reports. + * JPA implementation of {@link ReportManagement}. * */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service -public class ReportManagement { +public class JpaReportManagement implements ReportManagement { @Value("${spring.jpa.database}") private String databaseType; @@ -84,26 +80,19 @@ public class ReportManagement { @Autowired private TenantAware tenantAware; - /** - * Generates a report of all targets of their current update status count. - * For each {@link TargetUpdateStatus} an total count of targets which are - * in this status currently. - * - * @return a data report series which contains the target count for each - * target update status - */ + @Override @Cacheable("targetStatus") public DataReportSeries targetStatus() { final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); final CriteriaQuery query = cb.createQuery(Object[].class); - final Root targetRoot = query.from(Target.class); - final Join targetInfo = targetRoot.join(Target_.targetInfo); - final Expression countColumn = cb.count(targetInfo.get(TargetInfo_.targetId)); + final Root targetRoot = query.from(JpaTarget.class); + final Join targetInfo = targetRoot.join(JpaTarget_.targetInfo); + final Expression countColumn = cb.count(targetInfo.get(JpaTargetInfo_.targetId)); final CriteriaQuery multiselect = query - .multiselect(targetInfo.get(TargetInfo_.updateStatus), countColumn) - .groupBy(targetInfo.get(TargetInfo_.updateStatus)) - .orderBy(cb.desc(targetInfo.get(TargetInfo_.updateStatus))); + .multiselect(targetInfo.get(JpaTargetInfo_.updateStatus), countColumn) + .groupBy(targetInfo.get(JpaTargetInfo_.updateStatus)) + .orderBy(cb.desc(targetInfo.get(JpaTargetInfo_.updateStatus))); // | col1 | col2 | // | U_STATUS | COUNT | @@ -116,38 +105,24 @@ public class ReportManagement { return new DataReportSeries<>("Target Status Overview", reportSeriesItems); } - /** - * Generates a report of the top x distribution set assigned usage as a list - * of {@link InnerOuterDataReportSeries} which is ideal for generate a donut - * chart out of it. The inner series contains the distribution set names and - * total count usage. The outer series contains each version usage and its - * usage count. {@code inner: ds1:5 -> outer: vers 0.0.0:3, vers 1.0.0:2} - * {@code inner: ds2:1 -> outer: vers 0.0.1:1} - * - * The top x entries are seperated within the series, the rest of the - * distribution sets usage are summarized to a "misc" series. - * - * @param topXEntries - * the top entries which should be shown, the rest distribution - * set entries are summarized as "misc" - * @return a list of inner and outer series of distribution set usage - */ + @Override @Cacheable("distributionUsageAssigned") public List> distributionUsageAssigned(final int topXEntries) { // top X entries distribution usage final CriteriaBuilder cbTopX = entityManager.getCriteriaBuilder(); final CriteriaQuery queryTopX = cbTopX.createQuery(Object[].class); - final Root rootTopX = queryTopX.from(DistributionSet.class); - final ListJoin joinTopX = rootTopX.join(DistributionSet_.assignedToTargets, + final Root rootTopX = queryTopX.from(JpaDistributionSet.class); + final ListJoin joinTopX = rootTopX.join(JpaDistributionSet_.assignedToTargets, JoinType.LEFT); final Expression countColumn = cbTopX.count(joinTopX); // top x usage query final CriteriaQuery groupBy = queryTopX - .multiselect(rootTopX.get(DistributionSet_.name), rootTopX.get(DistributionSet_.version), countColumn) - .where(cbTopX.equal(rootTopX.get(DistributionSet_.deleted), false)) - .groupBy(rootTopX.get(DistributionSet_.name), rootTopX.get(DistributionSet_.version)) - .orderBy(cbTopX.desc(countColumn), cbTopX.asc(rootTopX.get(DistributionSet_.name))); + .multiselect(rootTopX.get(JpaDistributionSet_.name), rootTopX.get(JpaDistributionSet_.version), + countColumn) + .where(cbTopX.equal(rootTopX.get(JpaDistributionSet_.deleted), false)) + .groupBy(rootTopX.get(JpaDistributionSet_.name), rootTopX.get(JpaDistributionSet_.version)) + .orderBy(cbTopX.desc(countColumn), cbTopX.asc(rootTopX.get(JpaDistributionSet_.name))); // | col1 | col2 | col3 | // | NAME | VER | COUNT | final List resultListTop = entityManager.createQuery(groupBy).getResultList(); @@ -156,38 +131,23 @@ public class ReportManagement { return mapDistirbutionUsageResultToDataReport(topXEntries, resultListTop); } - /** - * Generates a report of the top x distribution set installed usage as a - * list of {@link InnerOuterDataReportSeries} which is ideal for generate a - * donut chart out of it. The inner series contains the distribution set - * names and total count usage. The outer series contains each version usage - * and its usage count. - * {@code inner: ds1:5 -> outer: vers 0.0.0:3, vers 1.0.0:2} - * {@code inner: ds2:1 -> outer: vers 0.0.1:1} - * - * The top x entries are seperated within the series, the rest of the - * distribution sets usage are summarized to a "misc" series. - * - * @param topXEntries - * the top entries which should be shown, the rest distribution - * set entries are summarized as "misc" - * @return a list of inner and outer series of distribution set usage - */ + @Override @Cacheable("distributionUsageInstalled") public List> distributionUsageInstalled(final int topXEntries) { // top X entries distribution usage final CriteriaBuilder cbTopX = entityManager.getCriteriaBuilder(); final CriteriaQuery queryTopX = cbTopX.createQuery(Object[].class); - final Root rootTopX = queryTopX.from(DistributionSet.class); - final ListJoin joinTopX = rootTopX.join(DistributionSet_.installedAtTargets, - JoinType.LEFT); + final Root rootTopX = queryTopX.from(JpaDistributionSet.class); + final ListJoin joinTopX = rootTopX + .join(JpaDistributionSet_.installedAtTargets, JoinType.LEFT); final Expression countColumn = cbTopX.count(joinTopX); // top x usage query final CriteriaQuery groupBy = queryTopX - .multiselect(rootTopX.get(DistributionSet_.name), rootTopX.get(DistributionSet_.version), countColumn) - .where(cbTopX.equal(rootTopX.get(DistributionSet_.deleted), false)) - .groupBy(rootTopX.get(DistributionSet_.name), rootTopX.get(DistributionSet_.version)) - .orderBy(cbTopX.desc(countColumn), cbTopX.asc(rootTopX.get(DistributionSet_.name))); + .multiselect(rootTopX.get(JpaDistributionSet_.name), rootTopX.get(JpaDistributionSet_.version), + countColumn) + .where(cbTopX.equal(rootTopX.get(JpaDistributionSet_.deleted), false)) + .groupBy(rootTopX.get(JpaDistributionSet_.name), rootTopX.get(JpaDistributionSet_.version)) + .orderBy(cbTopX.desc(countColumn), cbTopX.asc(rootTopX.get(JpaDistributionSet_.name))); // | col1 | col2 | col3 | // | NAME | VER | COUNT | final List resultListTop = entityManager.createQuery(groupBy).getResultList(); @@ -196,18 +156,7 @@ public class ReportManagement { return mapDistirbutionUsageResultToDataReport(topXEntries, resultListTop); } - /** - * Generates report for target created over period. - * - * @param dateType - * {@link PerMonth} - * @param from - * start date - * @param to - * end date - * @return DataReportSeries ListReportSeries list of target created - * count - */ + @Override @Cacheable("targetsCreatedOverPeriod") public DataReportSeries targetsCreatedOverPeriod(final DateType dateType, final LocalDateTime from, final LocalDateTime to) { @@ -258,23 +207,13 @@ public class ReportManagement { } } - /** - * Generates report for feedback over period. - * - * @param dateType - * {@link PerMonth} - * @param from - * start date - * @param to - * end date - * @return DataReportSeries ListReportSeries list of action status - * count - */ + @Override @Cacheable("feedbackReceivedOverTime") public DataReportSeries feedbackReceivedOverTime(final DateType dateType, final LocalDateTime from, final LocalDateTime to) { final Query createNativeQuery = entityManager .createNativeQuery(getFeedbackReceivedQueryTemplate(dateType, from, to)); + @SuppressWarnings("unchecked") final List resultList = createNativeQuery.getResultList(); final List> reportItems = resultList.stream() @@ -284,19 +223,7 @@ public class ReportManagement { return new DataReportSeries<>("FeedbackRecieved", reportItems); } - /** - * Generates a report as a {@link ListReportSeries} targets polled based on - * the {@link TargetStatus#getLastTargetQuery()} within an hour, day, week, - * month, year, more than a year, never. - * - * The order of the numbers within the {@link DataReportSeries} is the order - * hour, day, week, month, year, more than a year, never. - * - * @return a {@link DataReportSeries} which contains the number of targets - * which have not been polled in the last hour, day, ... year,more - * than a year, never. - * - */ + @Override @Cacheable("targetsLastPoll") public DataReportSeries targetsLastPoll() { @@ -349,15 +276,15 @@ public class ReportManagement { // count select statement final CriteriaQuery countSelect = cb.createQuery(Long.class); - final Root countSelectRoot = countSelect.from(Target.class); - final Join targetInfoJoin = countSelectRoot.join(Target_.targetInfo); + final Root countSelectRoot = countSelect.from(JpaTarget.class); + final Join targetInfoJoin = countSelectRoot.join(JpaTarget_.targetInfo); countSelect.select(cb.count(countSelectRoot)); if (start != null && end != null) { - countSelect.where(cb.between(targetInfoJoin.get(TargetInfo_.lastTargetQuery), start, end)); + countSelect.where(cb.between(targetInfoJoin.get(JpaTargetInfo_.lastTargetQuery), start, end)); } else if (from == null && to != null) { - countSelect.where(cb.lessThanOrEqualTo(targetInfoJoin.get(TargetInfo_.lastTargetQuery), end)); + countSelect.where(cb.lessThanOrEqualTo(targetInfoJoin.get(JpaTargetInfo_.lastTargetQuery), end)); } else { - countSelect.where(cb.isNull(targetInfoJoin.get(TargetInfo_.lastTargetQuery))); + countSelect.where(cb.isNull(targetInfoJoin.get(JpaTargetInfo_.lastTargetQuery))); } return countSelect; } @@ -504,80 +431,4 @@ 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(); - - private DateTypes() { - - } - - /** - * @return PerMonth - */ - public static PerMonth perMonth() { - return PER_MONTH; - } - } - - /** - * Data base format. - * - * - * - * @param - */ - public interface DateType { - /** - * @param s - * @return T - */ - T format(String s); - - /** - * h2 format. - * - * @return String - */ - String h2Format(); - - /** - * mysql format. - * - * @return String - */ - String mySqlFormat(); - } - - /** - * Gives the date format based on DB H2 or mySql. - * - * - * - */ - public static final class PerMonth implements DateType, Serializable { - private static final long serialVersionUID = 1L; - private static final String DATE_PATTERN = "yyyy-MM"; - - @Override - public LocalDate format(final String s) { - final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_PATTERN); - final YearMonth ym = YearMonth.parse(s, formatter); - return ym.atDay(1); - } - - @Override - public String h2Format() { - return DATE_PATTERN; - } - - @Override - public String mySqlFormat() { - return "%Y-%m"; - } - - } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java similarity index 51% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java index d204154d0..9f63204b1 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java @@ -6,8 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -19,20 +20,25 @@ import javax.persistence.criteria.Join; import javax.persistence.criteria.JoinType; import javax.persistence.criteria.ListJoin; import javax.persistence.criteria.Root; -import javax.validation.constraints.NotNull; -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.RolloutGroupFields; +import org.eclipse.hawkbit.repository.RolloutGroupManagement; +import org.eclipse.hawkbit.repository.TargetFields; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction_; +import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; +import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup_; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; +import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup; +import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup_; +import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.Action_; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.RolloutGroup_; -import org.eclipse.hawkbit.repository.model.RolloutTargetGroup; -import org.eclipse.hawkbit.repository.model.RolloutTargetGroup_; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetWithActionStatus; -import org.eclipse.hawkbit.repository.model.Target_; import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; import org.springframework.beans.factory.annotation.Autowired; @@ -41,20 +47,16 @@ import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; 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; /** - * RolloutGroupManagement to control rollout groups. This service secures all - * the functionality based on the {@link PreAuthorize} annotation on methods. + * JPA implementation of {@link RolloutGroupManagement}. */ @Validated -@Service @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -public class RolloutGroupManagement { +public class JpaRolloutGroupManagement implements RolloutGroupManagement { @Autowired private RolloutGroupRepository rolloutGroupRepository; @@ -68,68 +70,43 @@ public class RolloutGroupManagement { @Autowired private EntityManager entityManager; - /** - * Retrieves a single {@link RolloutGroup} by its ID. - * - * @param rolloutGroupId - * the ID of the rollout group to find - * @return the found {@link RolloutGroup} by its ID or {@code null} if it - * does not exists - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + @Override public RolloutGroup findRolloutGroupById(final Long rolloutGroupId) { return rolloutGroupRepository.findOne(rolloutGroupId); } - /** - * Retrieves a page of {@link RolloutGroup}s filtered by a given - * {@link Rollout}. - * - * @param rolloutId - * the ID of the rollout to filter the {@link RolloutGroup}s - * @param page - * the page request to sort and limit the result - * @return a page of found {@link RolloutGroup}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) - public Page findRolloutGroupsByRolloutId(final Long rolloutId, final Pageable page) { - return rolloutGroupRepository.findByRolloutId(rolloutId, page); + @Override + public Page findRolloutGroupsByRolloutId(final Long rolloutId, final Pageable pageable) { + return convertPage(rolloutGroupRepository.findByRolloutId(rolloutId, pageable), pageable); } - /** - * Retrieves a page of {@link RolloutGroup}s filtered by a given - * {@link Rollout} and the given {@link Specification}. - * - * @param rolloutId - * the ID of the rollout to filter the {@link RolloutGroup}s - * @param specification - * the specification to filter the result set based on attributes - * of the {@link RolloutGroup} - * @param page - * the page request to sort and limit the result - * @return a page of found {@link RolloutGroup}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) - public Page findRolloutGroupsByPredicate(final Rollout rollout, - final Specification specification, final Pageable page) { - return rolloutGroupRepository.findAll((root, query, criteriaBuilder) -> criteriaBuilder.and( - criteriaBuilder.equal(root.get(RolloutGroup_.rollout), rollout), - specification.toPredicate(root, query, criteriaBuilder)), page); + private static Page convertPage(final Page findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); } - /** - * Retrieves a page of {@link RolloutGroup}s filtered by a given - * {@link Rollout} with the detailed status. - * - * @param rolloutId - * the ID of the rollout to filter the {@link RolloutGroup}s - * @param page - * the page request to sort and limit the result - * @return a page of found {@link RolloutGroup}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) - public Page findAllRolloutGroupsWithDetailedStatus(final Long rolloutId, final Pageable page) { - final Page rolloutGroups = rolloutGroupRepository.findByRolloutId(rolloutId, page); + private static Page convertTPage(final Page findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + public Page findRolloutGroupsAll(final Rollout rollout, final String rsqlParam, + final Pageable pageable) { + + final Specification specification = RSQLUtility.parse(rsqlParam, RolloutGroupFields.class); + + return convertPage( + rolloutGroupRepository + .findAll( + (root, query, criteriaBuilder) -> criteriaBuilder.and( + criteriaBuilder.equal(root.get(JpaRolloutGroup_.rollout), rollout), + specification.toPredicate(root, query, criteriaBuilder)), + pageable), + pageable); + } + + @Override + public Page findAllRolloutGroupsWithDetailedStatus(final Long rolloutId, final Pageable pageable) { + final Page rolloutGroups = rolloutGroupRepository.findByRolloutId(rolloutId, pageable); final List rolloutGroupIds = rolloutGroups.getContent().stream().map(rollout -> rollout.getId()) .collect(Collectors.toList()); final Map> allStatesForRollout = getStatusCountItemForRolloutGroup( @@ -141,17 +118,10 @@ public class RolloutGroupManagement { rolloutGroup.setTotalTargetCountStatus(totalTargetCountStatus); } - return rolloutGroups; + return convertPage(rolloutGroups, pageable); } - /** - * Get count of targets in different status in rollout group. - * - * @param rolloutGroupId - * rollout group id - * @return rolloutGroup with details of targets count for different statuses - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + @Override public RolloutGroup findRolloutGroupWithDetailedStatus(final Long rolloutGroupId) { final RolloutGroup rolloutGroup = findRolloutGroupById(rolloutGroupId); final List rolloutStatusCountItems = actionRepository @@ -171,78 +141,45 @@ public class RolloutGroupManagement { return resultList.stream().collect(Collectors.groupingBy(TotalTargetCountActionStatus::getId)); } - /** - * Get targets of specified rollout group. - * - * @param rolloutGroup - * rollout group - * @param specification - * the specification for filtering the targets of a rollout group - * @param page - * the page request to sort and limit the result - * - * @return Page list of targets of a rollout group - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) - public Page findRolloutGroupTargets(final RolloutGroup rolloutGroup, - final Specification specification, final Pageable page) { - return targetRepository.findAll((root, query, criteriaBuilder) -> { - final ListJoin rolloutTargetJoin = root.join(Target_.rolloutTargetGroup); - return criteriaBuilder.and(specification.toPredicate(root, query, criteriaBuilder), + @Override + public Page findRolloutGroupTargets(final RolloutGroup rolloutGroup, final String rsqlParam, + final Pageable pageable) { + + final Specification rsqlSpecification = RSQLUtility.parse(rsqlParam, TargetFields.class); + + return convertTPage(targetRepository.findAll((root, query, criteriaBuilder) -> { + final ListJoin rolloutTargetJoin = root.join(JpaTarget_.rolloutTargetGroup); + return criteriaBuilder.and(rsqlSpecification.toPredicate(root, query, criteriaBuilder), criteriaBuilder.equal(rolloutTargetJoin.get(RolloutTargetGroup_.rolloutGroup), rolloutGroup)); - }, page); + }, pageable), pageable); } - /** - * Get targets of specified rollout group. - * - * @param rolloutGroup - * rollout group - * @param page - * the page request to sort and limit the result - * - * @return Page list of targets of a rollout group - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) - public Page findRolloutGroupTargets(@NotNull final RolloutGroup rolloutGroup, final Pageable page) { + @Override + public Page findRolloutGroupTargets(final RolloutGroup rolloutGroup, final Pageable page) { if (isRolloutStatusReady(rolloutGroup)) { // in case of status ready the action has not been created yet and // the relation information between target and rollout-group is // stored in the #TargetRolloutGroup. return targetRepository.findByRolloutTargetGroupRolloutGroupId(rolloutGroup.getId(), page); } - return targetRepository.findByActionsRolloutGroup(rolloutGroup, page); + return targetRepository.findByActionsRolloutGroup((JpaRolloutGroup) rolloutGroup, page); } private static boolean isRolloutStatusReady(final RolloutGroup rolloutGroup) { return rolloutGroup != null && RolloutStatus.READY.equals(rolloutGroup.getRollout().getStatus()); } - /** - * - * Find all targets with action status by rollout group id. The action - * status might be {@code null} if for the target within the rollout no - * actions as been created, e.g. the target already had assigned the same - * distribution set we do not create an action for it but the target is in - * the result list of the rollout-group. - * - * @param pageRequest - * the page request to sort and limit the result - * @param rolloutGroup - * rollout group - * @return {@link TargetWithActionStatus} target with action status - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + @Override public Page findAllTargetsWithActionStatus(final PageRequest pageRequest, - @NotNull final RolloutGroup rolloutGroup) { + final RolloutGroup rolloutGroup) { final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); final CriteriaQuery query = cb.createQuery(Object[].class); final CriteriaQuery countQuery = cb.createQuery(Long.class); final Root targetRoot = query.distinct(true).from(RolloutTargetGroup.class); - final Join targetJoin = targetRoot.join(RolloutTargetGroup_.target); - final ListJoin actionJoin = targetRoot.join(RolloutTargetGroup_.actions, + final Join targetJoin = targetRoot.join(RolloutTargetGroup_.target); + final ListJoin actionJoin = targetRoot.join(RolloutTargetGroup_.actions, JoinType.LEFT); final Root countQueryFrom = countQuery.distinct(true).from(RolloutTargetGroup.class); @@ -252,7 +189,7 @@ public class RolloutGroupManagement { .where(cb.equal(countQueryFrom.get(RolloutTargetGroup_.rolloutGroup), rolloutGroup)); final Long totalCount = entityManager.createQuery(countQuery).getSingleResult(); - final CriteriaQuery multiselect = query.multiselect(targetJoin, actionJoin.get(Action_.status)) + final CriteriaQuery multiselect = query.multiselect(targetJoin, actionJoin.get(JpaAction_.status)) .where(cb.equal(targetRoot.get(RolloutTargetGroup_.rolloutGroup), rolloutGroup)); final List targetWithActionStatus = entityManager.createQuery(multiselect) .setFirstResult(pageRequest.getOffset()).setMaxResults(pageRequest.getPageSize()).getResultList() @@ -260,4 +197,5 @@ public class RolloutGroupManagement { .collect(Collectors.toList()); return new PageImpl<>(targetWithActionStatus, pageRequest, totalCount); } + } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java similarity index 62% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java index 09decfc03..239302a70 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java @@ -6,8 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -16,30 +17,35 @@ import java.util.concurrent.Executor; import java.util.stream.Collectors; import javax.persistence.EntityManager; -import javax.validation.constraints.NotNull; -import org.eclipse.hawkbit.cache.CacheWriteNotify; -import org.eclipse.hawkbit.eventbus.event.RolloutGroupCreatedEvent; -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.DeploymentManagement; +import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; +import org.eclipse.hawkbit.repository.RolloutFields; +import org.eclipse.hawkbit.repository.RolloutManagement; +import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException; +import org.eclipse.hawkbit.repository.jpa.cache.CacheWriteNotify; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; +import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout_; +import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup; +import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupActionEvaluator; +import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupConditionEvaluator; +import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; -import org.eclipse.hawkbit.repository.model.RolloutTargetGroup; -import org.eclipse.hawkbit.repository.model.Rollout_; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetWithActionType; import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; -import org.eclipse.hawkbit.rollout.condition.RolloutGroupActionEvaluator; -import org.eclipse.hawkbit.rollout.condition.RolloutGroupConditionEvaluator; -import org.hibernate.validator.constraints.NotEmpty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; @@ -47,15 +53,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.annotation.Isolation; @@ -67,15 +71,11 @@ import org.springframework.util.Assert; import org.springframework.validation.annotation.Validated; /** - * RolloutManagement to control rollouts e.g. like creating, starting, resuming - * and pausing rollouts. This service secures all the functionality based on the - * {@link PreAuthorize} annotation on methods. + * JPA implementation of {@link RolloutManagement}. */ @Validated -@Service -@EnableScheduling @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -public class RolloutManagement { +public class JpaRolloutManagement implements RolloutManagement { private static final Logger LOGGER = LoggerFactory.getLogger(RolloutManagement.class); @Autowired @@ -134,122 +134,49 @@ public class RolloutManagement { */ private static final Set startingRollouts = ConcurrentHashMap.newKeySet(); - /** - * Retrieves all rollouts. - * - * @param page - * the page request to sort and limit the result - * @return a page of found rollouts - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) - public Page findAll(final Pageable page) { - return rolloutRepository.findAll(page); + @Override + public Page findAll(final Pageable pageable) { + return convertPage(rolloutRepository.findAll(pageable), pageable); } - /** - * Retrieves all rollouts found by the given specification. - * - * @param specification - * the specification to filter rollouts - * @param page - * the page request to sort and limit the result - * @return a page of found rollouts - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) - public Page findAllWithDetailedStatusByPredicate(final Specification specification, - final Pageable page) { - final Page findAll = rolloutRepository.findAll(specification, page); + private static Page convertPage(final Page findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + private static Slice convertPage(final Slice findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, 0); + } + + @Override + public Page findAllWithDetailedStatusByPredicate(final String rsqlParam, final Pageable pageable) { + + final Specification specification = RSQLUtility.parse(rsqlParam, RolloutFields.class); + + final Page findAll = rolloutRepository.findAll(specification, pageable); setRolloutStatusDetails(findAll); - return findAll; + return convertPage(findAll, pageable); } - /** - * 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 - * not exists - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + @Override public Rollout findRolloutById(final Long rolloutId) { return rolloutRepository.findOne(rolloutId); } - /** - * Persists a new rollout entity. The filter within the - * {@link Rollout#getTargetFilterQuery()} is used to retrieve the targets - * 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 - * the amount of groups to split the rollout into - * @param conditions - * 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. - */ + @Override @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) public Rollout createRollout(final Rollout rollout, final int amountGroup, final RolloutGroupConditions conditions) { - final Rollout savedRollout = createRollout(rollout, amountGroup); + final JpaRollout savedRollout = createRollout((JpaRollout) rollout, amountGroup); return createRolloutGroups(amountGroup, conditions, savedRollout); } - /** - * Persists a new rollout entity. The filter within the - * {@link Rollout#getTargetFilterQuery()} is used to retrieve the targets - * which are effected by this rollout to create. The creation of the rollout - * 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 - * the number of groups should be created for the rollout and - * split up the targets - * @param conditions - * the rolloutgroup conditions and actions which should be - * applied for each {@link RolloutGroup} - * @return the created rollout entity in state - * {@link RolloutStatus#CREATING} - */ + @Override @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) public Rollout createRolloutAsync(final Rollout rollout, final int amountGroup, final RolloutGroupConditions conditions) { - final Rollout savedRollout = createRollout(rollout, amountGroup); + final JpaRollout savedRollout = createRollout((JpaRollout) rollout, amountGroup); creatingRollouts.add(savedRollout.getName()); // need to flush the entity manager here to get the ID of the rollout, // because entity manager is set to FlushMode#Auto, entitymanager will @@ -269,7 +196,7 @@ public class RolloutManagement { return savedRollout; } - private Rollout createRollout(final Rollout rollout, final int amountGroup) { + private JpaRollout createRollout(final JpaRollout rollout, final int amountGroup) { verifyRolloutGroupParameter(amountGroup); final Long totalTargets = targetManagement.countTargetByTargetFilterQuery(rollout.getTargetFilterQuery()); rollout.setTotalTargets(totalTargets.longValue()); @@ -285,7 +212,7 @@ public class RolloutManagement { } private Rollout createRolloutGroupsInNewTransaction(final int amountOfGroups, - final RolloutGroupConditions conditions, final Rollout savedRollout) { + final RolloutGroupConditions conditions, final JpaRollout savedRollout) { final DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setName("creatingRollout"); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); @@ -308,7 +235,7 @@ public class RolloutManagement { * @return the rollout with created groups */ private Rollout createRolloutGroups(final int amountOfGroups, final RolloutGroupConditions conditions, - final Rollout savedRollout) { + final JpaRollout savedRollout) { int pageIndex = 0; int groupIndex = 0; final Long totalCount = savedRollout.getTotalTargets(); @@ -324,7 +251,7 @@ public class RolloutManagement { while (pageIndex < totalCount) { groupIndex++; final String nameAndDesc = "group-" + groupIndex; - final RolloutGroup group = new RolloutGroup(); + final JpaRolloutGroup group = new JpaRolloutGroup(); group.setName(nameAndDesc); group.setDescription(nameAndDesc); group.setRollout(savedRollout); @@ -336,7 +263,7 @@ public class RolloutManagement { group.setErrorAction(conditions.getErrorAction()); group.setErrorActionExp(conditions.getErrorActionExp()); - final RolloutGroup savedGroup = rolloutGroupRepository.save(group); + final JpaRolloutGroup savedGroup = rolloutGroupRepository.save(group); final Slice targetGroup = targetManagement.findTargetsAll(savedRollout.getTargetFilterQuery(), new OffsetBasedPageRequest(pageIndex, groupSize, new Sort(Direction.ASC, "id"))); @@ -355,62 +282,23 @@ public class RolloutManagement { return rolloutRepository.save(savedRollout); } - /** - * Starts a rollout which has been created. The rollout must be in - * {@link RolloutStatus#READY} state. The according actions will be created - * 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. - */ + @Override @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_SYSTEM_CODE) public Rollout startRollout(final Rollout rollout) { - final Rollout mergedRollout = entityManager.merge(rollout); + final JpaRollout mergedRollout = entityManager.merge((JpaRollout) rollout); checkIfRolloutCanStarted(rollout, mergedRollout); return doStartRollout(mergedRollout); } - /** - * Starts a rollout asynchronously which has been created. The rollout must - * be in {@link RolloutStatus#READY} state. The according actions will be - * created asynchronously 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 the started rollout - * - * @throws RolloutIllegalStateException - * if given rollout is not in {@link RolloutStatus#READY}. Only - * ready rollouts can be started. - */ - @Transactional + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_SYSTEM_CODE) public Rollout startRolloutAsync(final Rollout rollout) { - final Rollout mergedRollout = entityManager.merge(rollout); + final JpaRollout mergedRollout = entityManager.merge((JpaRollout) rollout); checkIfRolloutCanStarted(rollout, mergedRollout); mergedRollout.setStatus(RolloutStatus.STARTING); - final Rollout updatedRollout = rolloutRepository.save(mergedRollout); + final JpaRollout updatedRollout = rolloutRepository.save(mergedRollout); startingRollouts.add(updatedRollout.getName()); executor.execute(() -> { try { @@ -429,13 +317,13 @@ public class RolloutManagement { } - private Rollout doStartRollout(final Rollout rollout) { + private Rollout doStartRollout(final JpaRollout rollout) { final DistributionSet distributionSet = rollout.getDistributionSet(); final ActionType actionType = rollout.getActionType(); final long forceTime = rollout.getForcedTime(); - final List rolloutGroups = rolloutGroupRepository.findByRolloutOrderByIdAsc(rollout); + final List rolloutGroups = rolloutGroupRepository.findByRolloutOrderByIdAsc(rollout); for (int iGroup = 0; iGroup < rolloutGroups.size(); iGroup++) { - final RolloutGroup rolloutGroup = rolloutGroups.get(iGroup); + final JpaRolloutGroup rolloutGroup = rolloutGroups.get(iGroup); final List targetGroup = targetRepository.findByRolloutTargetGroupRolloutGroup(rolloutGroup); // firstgroup can already be started if (iGroup == 0) { @@ -458,31 +346,11 @@ public class RolloutManagement { return rolloutRepository.save(rollout); } - /** - * Pauses a rollout which is currently running. The Rollout switches - * {@link RolloutStatus#PAUSED}. {@link RolloutGroup}s which are currently - * running will be untouched. {@link RolloutGroup}s which are - * {@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. - */ + @Override @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_SYSTEM_CODE) public void pauseRollout(final Rollout rollout) { - final Rollout mergedRollout = entityManager.merge(rollout); + final JpaRollout mergedRollout = entityManager.merge((JpaRollout) rollout); if (mergedRollout.getStatus() != RolloutStatus.RUNNING) { throw new RolloutIllegalStateException("Rollout can only be paused in state running but current state is " + rollout.getStatus().name().toLowerCase()); @@ -496,23 +364,11 @@ public class RolloutManagement { rolloutRepository.save(mergedRollout); } - /** - * 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. - */ + @Override @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_SYSTEM_CODE) public void resumeRollout(final Rollout rollout) { - final Rollout mergedRollout = entityManager.merge(rollout); + final JpaRollout mergedRollout = entityManager.merge((JpaRollout) rollout); if (!(RolloutStatus.PAUSED.equals(mergedRollout.getStatus()))) { throw new RolloutIllegalStateException("Rollout can only be resumed in state paused but current state is " + rollout.getStatus().name().toLowerCase()); @@ -521,38 +377,9 @@ public class RolloutManagement { rolloutRepository.save(mergedRollout); } - /** - * 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() {
-     *     public Void call() throws Exception {
-     *        //run system-code
-     *     }
-     * });
-     *  }
-     * 
- * - * 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 - * less than (lastcheck-delay). - */ + @Override @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_UNCOMMITTED) @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_SYSTEM_CODE) public void checkRunningRollouts(final long delayBetweenChecks) { verifyStuckedRollouts(); final long lastCheck = System.currentTimeMillis(); @@ -566,13 +393,13 @@ public class RolloutManagement { return; } - final List rolloutsToCheck = rolloutRepository.findByLastCheckAndStatus(lastCheck, + final List rolloutsToCheck = rolloutRepository.findByLastCheckAndStatus(lastCheck, RolloutStatus.RUNNING); LOGGER.info("Found {} running rollouts to check", rolloutsToCheck.size()); - for (final Rollout rollout : rolloutsToCheck) { + for (final JpaRollout rollout : rolloutsToCheck) { LOGGER.debug("Checking rollout {}", rollout); - final List rolloutGroups = rolloutGroupRepository.findByRolloutAndStatus(rollout, + final List rolloutGroups = rolloutGroupRepository.findByRolloutAndStatus(rollout, RolloutGroupStatus.RUNNING); if (rolloutGroups.isEmpty()) { @@ -602,7 +429,7 @@ public class RolloutManagement { * In case this happens, set the rollout to error state. */ private void verifyStuckedRollouts() { - final List rolloutsInCreatingState = rolloutRepository.findByStatus(RolloutStatus.CREATING); + final List rolloutsInCreatingState = rolloutRepository.findByStatus(RolloutStatus.CREATING); rolloutsInCreatingState.stream().filter(rollout -> !creatingRollouts.contains(rollout.getName())) .forEach(rollout -> { LOGGER.warn( @@ -612,7 +439,7 @@ public class RolloutManagement { rolloutRepository.save(rollout); }); - final List rolloutsInStartingState = rolloutRepository.findByStatus(RolloutStatus.STARTING); + final List rolloutsInStartingState = rolloutRepository.findByStatus(RolloutStatus.STARTING); rolloutsInStartingState.stream().filter(rollout -> !startingRollouts.contains(rollout.getName())) .forEach(rollout -> { LOGGER.warn( @@ -624,8 +451,8 @@ public class RolloutManagement { } - private void executeRolloutGroups(final Rollout rollout, final List rolloutGroups) { - for (final RolloutGroup rolloutGroup : rolloutGroups) { + private void executeRolloutGroups(final JpaRollout rollout, final List rolloutGroups) { + for (final JpaRolloutGroup rolloutGroup : rolloutGroups) { // error state check, do we need to stop the whole // rollout because of error? final RolloutGroupErrorCondition errorCondition = rolloutGroup.getErrorCondition(); @@ -646,8 +473,8 @@ public class RolloutManagement { } } - private void executeLatestRolloutGroup(final Rollout rollout) { - final List latestRolloutGroup = rolloutGroupRepository + private void executeLatestRolloutGroup(final JpaRollout rollout) { + final List latestRolloutGroup = rolloutGroupRepository .findByRolloutAndStatusNotOrderByIdDesc(rollout, RolloutGroupStatus.SCHEDULED); if (latestRolloutGroup.isEmpty()) { return; @@ -665,13 +492,13 @@ public class RolloutManagement { } } - private boolean isRolloutComplete(final Rollout rollout) { + private boolean isRolloutComplete(final JpaRollout rollout) { final Long groupsActiveLeft = rolloutGroupRepository.countByRolloutAndStatusOrStatus(rollout, RolloutGroupStatus.RUNNING, RolloutGroupStatus.SCHEDULED); return groupsActiveLeft == 0; } - private boolean isRolloutGroupComplete(final Rollout rollout, final RolloutGroup rolloutGroup) { + private boolean isRolloutGroupComplete(final JpaRollout rollout, final JpaRolloutGroup rolloutGroup) { final Long actionsLeftForRollout = actionRepository .countByRolloutAndRolloutGroupAndStatusNotAndStatusNotAndStatusNot(rollout, rolloutGroup, Action.Status.ERROR, Action.Status.FINISHED, Action.Status.CANCELED); @@ -720,65 +547,35 @@ public class RolloutManagement { rolloutGroup, rolloutGroup.getSuccessActionExp()); } - /** - * Counts all {@link Target}s in the repository. - * - * @return number of targets - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + @Override public Long countRolloutsAll() { return rolloutRepository.count(); } - /** - * Count rollouts by specified filter text. - * - * @param searchText - * name or description - * @return total count rollouts for specified filter text. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + @Override public Long countRolloutsAllByFilters(final String searchText) { return rolloutRepository.count(likeNameOrDescription(searchText)); } - private static Specification likeNameOrDescription(final String searchText) { + private static Specification likeNameOrDescription(final String searchText) { return (rolloutRoot, query, criteriaBuilder) -> { final String searchTextToLower = searchText.toLowerCase(); return criteriaBuilder.or( - criteriaBuilder.like(criteriaBuilder.lower(rolloutRoot.get(Rollout_.name)), searchTextToLower), - criteriaBuilder.like(criteriaBuilder.lower(rolloutRoot.get(Rollout_.description)), + criteriaBuilder.like(criteriaBuilder.lower(rolloutRoot.get(JpaRollout_.name)), searchTextToLower), + criteriaBuilder.like(criteriaBuilder.lower(rolloutRoot.get(JpaRollout_.description)), searchTextToLower)); }; } - /** - * * Retrieves a specific rollout by its ID. - * - * @param pageable - * the page request to sort and limit the result - * @param searchText - * search text which matches name or description of rollout - * @return the founded rollout or {@code null} if rollout with given ID does - * not exists - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) - public Slice findRolloutByFilters(final Pageable pageable, @NotEmpty final String searchText) { - final Specification specs = likeNameOrDescription(searchText); - final Slice findAll = criteriaNoCountDao.findAll(specs, pageable, Rollout.class); + @Override + public Slice findRolloutByFilters(final Pageable pageable, final String searchText) { + final Specification specs = likeNameOrDescription(searchText); + final Slice findAll = criteriaNoCountDao.findAll(specs, pageable, JpaRollout.class); setRolloutStatusDetails(findAll); - return findAll; + return convertPage(findAll, pageable); } - /** - * 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 - * does not exists - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + @Override public Rollout findRolloutByName(final String rolloutName) { return rolloutRepository.findByName(rolloutName); } @@ -791,13 +588,12 @@ public class RolloutManagement { * * @return Rollout updated rollout */ - @NotNull + @Override @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) - public Rollout updateRollout(@NotNull final Rollout rollout) { + public Rollout updateRollout(final Rollout rollout) { Assert.notNull(rollout.getId()); - return rolloutRepository.save(rollout); + return rolloutRepository.save((JpaRollout) rollout); } /** @@ -809,30 +605,22 @@ public class RolloutManagement { * statuses * */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) - public Page findAllRolloutsWithDetailedStatus(final Pageable page) { - final Page rollouts = findAll(page); + @Override + public Page findAllRolloutsWithDetailedStatus(final Pageable pageable) { + final Page rollouts = rolloutRepository.findAll(pageable); setRolloutStatusDetails(rollouts); - return rollouts; + return convertPage(rollouts, pageable); } - /** - * Get count of targets in different status in rollout. - * - * @param rolloutId - * rollout id - * @return rollout details of targets count for different statuses - * - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + @Override public Rollout findRolloutWithDetailedStatus(final Long rolloutId) { final Rollout rollout = findRolloutById(rolloutId); final List rolloutStatusCountItems = actionRepository .getStatusCountByRolloutId(rolloutId); final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(rolloutStatusCountItems, rollout.getTotalTargets()); - rollout.setTotalTargetCountStatus(totalTargetCountStatus); + ((JpaRollout) rollout).setTotalTargetCountStatus(totalTargetCountStatus); return rollout; } @@ -841,7 +629,7 @@ public class RolloutManagement { return resultList.stream().collect(Collectors.groupingBy(TotalTargetCountActionStatus::getId)); } - private void setRolloutStatusDetails(final Slice rollouts) { + private void setRolloutStatusDetails(final Slice rollouts) { final List rolloutIds = rollouts.getContent().stream().map(rollout -> rollout.getId()) .collect(Collectors.toList()); final Map> allStatesForRollout = getStatusCountItemForRollout( @@ -850,7 +638,7 @@ public class RolloutManagement { for (final Rollout rollout : rollouts) { final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus( allStatesForRollout.get(rollout.getId()), rollout.getTotalTargets()); - rollout.setTotalTargetCountStatus(totalTargetCountStatus); + ((JpaRollout) rollout).setTotalTargetCountStatus(totalTargetCountStatus); } } @@ -861,16 +649,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 - * the ID of the {@link RolloutGroup} - * @return percentage finished - */ + @Override public float getFinishedPercentForRunningGroup(final Long rolloutId, final RolloutGroup rolloutGroup) { final Long totalGroup = rolloutGroup.getTotalTargets(); final Long finished = actionRepository.countByRolloutIdAndRolloutGroupIdAndStatus(rolloutId, @@ -883,4 +662,5 @@ public class RolloutManagement { // calculate threshold return ((float) finished / (float) totalGroup) * 100; } + } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java new file mode 100644 index 000000000..b561667a9 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java @@ -0,0 +1,663 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.ListJoin; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.ArtifactManagement; +import org.eclipse.hawkbit.repository.SoftwareManagement; +import org.eclipse.hawkbit.repository.SoftwareModuleFields; +import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields; +import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata_; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_; +import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey; +import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification; +import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; +import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.AuditorAware; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import com.google.common.base.Strings; +import com.google.common.collect.Sets; + +/** + * JPA implementation of {@link SoftwareManagement}. + * + */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) +@Validated +public class JpaSoftwareManagement implements SoftwareManagement { + + @Autowired + private EntityManager entityManager; + + @Autowired + private DistributionSetRepository distributionSetRepository; + + @Autowired + private DistributionSetTypeRepository distributionSetTypeRepository; + + @Autowired + private SoftwareModuleRepository softwareModuleRepository; + + @Autowired + private SoftwareModuleMetadataRepository softwareModuleMetadataRepository; + + @Autowired + private SoftwareModuleTypeRepository softwareModuleTypeRepository; + + @Autowired + private NoCountPagingRepository criteriaNoCountDao; + + @Autowired + private AuditorAware auditorProvider; + + @Autowired + private ArtifactManagement artifactManagement; + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModule updateSoftwareModule(final SoftwareModule sm) { + checkNotNull(sm.getId()); + + final JpaSoftwareModule module = softwareModuleRepository.findOne(sm.getId()); + + boolean updated = false; + if (null == sm.getDescription() || !sm.getDescription().equals(module.getDescription())) { + module.setDescription(sm.getDescription()); + updated = true; + } + if (null == sm.getVendor() || !sm.getVendor().equals(module.getVendor())) { + module.setVendor(sm.getVendor()); + updated = true; + } + + return updated ? softwareModuleRepository.save(module) : module; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModuleType updateSoftwareModuleType(final SoftwareModuleType sm) { + checkNotNull(sm.getId()); + + final JpaSoftwareModuleType type = softwareModuleTypeRepository.findOne(sm.getId()); + + boolean updated = false; + if (sm.getDescription() == null || !sm.getDescription().equals(type.getDescription())) { + type.setDescription(sm.getDescription()); + updated = true; + } + if (sm.getColour() != null && !sm.getColour().equals(type.getColour())) { + type.setColour(sm.getColour()); + updated = true; + } + return updated ? softwareModuleTypeRepository.save(type) : type; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModule createSoftwareModule(final SoftwareModule swModule) { + if (null != swModule.getId()) { + throw new EntityAlreadyExistsException(); + } + return softwareModuleRepository.save((JpaSoftwareModule) swModule); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List createSoftwareModule(final Collection swModules) { + swModules.forEach(swModule -> { + if (null != swModule.getId()) { + throw new EntityAlreadyExistsException(); + } + }); + + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Collection jpaCast = (Collection) swModules; + + return new ArrayList<>(softwareModuleRepository.save(jpaCast)); + } + + @Override + public Slice findSoftwareModulesByType(final Pageable pageable, final SoftwareModuleType type) { + + final List> specList = new LinkedList<>(); + + Specification spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + + spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); + } + + private static Slice convertSmPage(final Slice findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, 0); + } + + private static Page convertSmPage(final Page findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + private static Page convertSmMdPage(final Page findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + public Long countSoftwareModulesByType(final SoftwareModuleType type) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + + spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + return countSwModuleByCriteriaAPI(specList); + } + + @Override + public SoftwareModule findSoftwareModuleById(final Long id) { + return artifactManagement.findSoftwareModuleById(id); + } + + @Override + public SoftwareModule findSoftwareModuleByNameAndVersion(final String name, final String version, + final SoftwareModuleType type) { + + return softwareModuleRepository.findOneByNameAndVersionAndType(name, version, (JpaSoftwareModuleType) type); + } + + private boolean isUnassigned(final JpaSoftwareModule bsmMerged) { + return distributionSetRepository.findByModules(bsmMerged).isEmpty(); + } + + private Slice findSwModuleByCriteriaAPI(final Pageable pageable, + final List> specList) { + return criteriaNoCountDao.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable, + JpaSoftwareModule.class); + } + + private Long countSwModuleByCriteriaAPI(final List> specList) { + return softwareModuleRepository.count(SpecificationsBuilder.combineWithAnd(specList)); + } + + private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) { + for (final LocalArtifact localArtifact : swModule.getLocalArtifacts()) { + artifactManagement.deleteLocalArtifact(localArtifact); + } + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteSoftwareModules(final Collection ids) { + final List swModulesToDelete = softwareModuleRepository.findByIdIn(ids); + final Set assignedModuleIds = new HashSet<>(); + swModulesToDelete.forEach(swModule -> { + + // delete binary data of artifacts + deleteGridFsArtifacts(swModule); + + if (isUnassigned(swModule)) { + + softwareModuleRepository.delete(swModule); + + } else { + + assignedModuleIds.add(swModule.getId()); + } + }); + + if (!assignedModuleIds.isEmpty()) { + String currentUser = null; + if (auditorProvider != null) { + currentUser = auditorProvider.getCurrentAuditor(); + } + softwareModuleRepository.deleteSoftwareModule(System.currentTimeMillis(), currentUser, + assignedModuleIds.toArray(new Long[0])); + } + } + + @Override + public Slice findSoftwareModulesAll(final Pageable pageable) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + spec = (root, query, cb) -> { + if (!query.getResultType().isAssignableFrom(Long.class)) { + root.fetch(JpaSoftwareModule_.type); + } + return cb.conjunction(); + }; + + specList.add(spec); + + return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); + } + + @Override + public Long countSoftwareModulesAll() { + + final List> specList = new ArrayList<>(); + + final Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + return countSwModuleByCriteriaAPI(specList); + } + + @Override + public SoftwareModule findSoftwareModuleWithDetails(final Long id) { + return artifactManagement.findSoftwareModuleWithDetails(id); + } + + @Override + public Page findSoftwareModulesByPredicate(final String rsqlParam, final Pageable pageable) { + final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class); + + return convertSmPage(softwareModuleRepository.findAll(spec, pageable), pageable); + } + + @Override + public Page findSoftwareModuleTypesAll(final String rsqlParam, final Pageable pageable) { + + final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class); + + return convertSmTPage(softwareModuleTypeRepository.findAll(spec, pageable), pageable); + } + + private static Page convertSmTPage(final Page findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + public List findSoftwareModulesById(final Collection ids) { + return new ArrayList<>(softwareModuleRepository.findByIdIn(ids)); + } + + @Override + public Slice findSoftwareModuleByFilters(final Pageable pageable, final String searchText, + final SoftwareModuleType type) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + if (!Strings.isNullOrEmpty(searchText)) { + spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); + specList.add(spec); + } + + if (null != type) { + spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + } + + spec = (root, query, cb) -> { + if (!query.getResultType().isAssignableFrom(Long.class)) { + root.fetch(JpaSoftwareModule_.type); + } + return cb.conjunction(); + }; + + specList.add(spec); + + return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); + } + + @Override + public Slice findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc( + final Pageable pageable, final Long orderByDistributionId, final String searchText, + final SoftwareModuleType ty) { + final JpaSoftwareModuleType type = (JpaSoftwareModuleType) ty; + + final List resultList = new ArrayList<>(); + final int pageSize = pageable.getPageSize(); + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + + // get the assigned software modules + final CriteriaQuery assignedQuery = cb.createQuery(JpaSoftwareModule.class); + final Root assignedRoot = assignedQuery.from(JpaSoftwareModule.class); + assignedQuery.distinct(true); + final ListJoin assignedDsJoin = assignedRoot + .join(JpaSoftwareModule_.assignedTo); + // build the specifications and then to predicates necessary by the + // given filters + final Predicate[] specPredicate = specificationsToPredicate(buildSpecificationList(searchText, type), + assignedRoot, assignedQuery, cb, + cb.equal(assignedDsJoin.get(JpaDistributionSet_.id), orderByDistributionId)); + // if we have some predicates then add it to the where clause of the + // multi select + assignedQuery.where(specPredicate); + assignedQuery.orderBy(cb.asc(assignedRoot.get(JpaSoftwareModule_.name)), + cb.asc(assignedRoot.get(JpaSoftwareModule_.version))); + // don't page the assigned query on database, we need all assigned + // software modules to filter + // them out in the unassigned query + final List assignedSoftwareModules = entityManager.createQuery(assignedQuery) + .getResultList(); + // map result + if (pageable.getOffset() < assignedSoftwareModules.size()) { + assignedSoftwareModules + .subList(pageable.getOffset(), Math.min(assignedSoftwareModules.size(), pageable.getPageSize())) + .forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, true))); + } + + if (assignedSoftwareModules.size() >= pageSize) { + return new SliceImpl<>(resultList); + } + + // get the unassigned software modules + final CriteriaQuery unassignedQuery = cb.createQuery(JpaSoftwareModule.class); + unassignedQuery.distinct(true); + final Root unassignedRoot = unassignedQuery.from(JpaSoftwareModule.class); + + Predicate[] unassignedSpec; + if (!assignedSoftwareModules.isEmpty()) { + unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, + unassignedQuery, cb, cb.not(unassignedRoot.get(JpaSoftwareModule_.id) + .in(assignedSoftwareModules.stream().map(sw -> sw.getId()).collect(Collectors.toList())))); + } else { + unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, + unassignedQuery, cb); + } + + unassignedQuery.where(unassignedSpec); + unassignedQuery.orderBy(cb.asc(unassignedRoot.get(JpaSoftwareModule_.name)), + cb.asc(unassignedRoot.get(JpaSoftwareModule_.version))); + final List unassignedSoftwareModules = entityManager.createQuery(unassignedQuery) + .setFirstResult(Math.max(0, pageable.getOffset() - assignedSoftwareModules.size())) + .setMaxResults(pageSize).getResultList(); + // map result + unassignedSoftwareModules.forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, false))); + + return new SliceImpl<>(resultList); + } + + private static List> buildSpecificationList(final String searchText, + final JpaSoftwareModuleType type) { + final List> specList = new ArrayList<>(); + if (!Strings.isNullOrEmpty(searchText)) { + specList.add(SoftwareModuleSpecification.likeNameOrVersion(searchText)); + } + if (type != null) { + specList.add(SoftwareModuleSpecification.equalType(type)); + } + specList.add(SoftwareModuleSpecification.isDeletedFalse()); + return specList; + } + + private Predicate[] specificationsToPredicate(final List> specifications, + final Root root, final CriteriaQuery query, final CriteriaBuilder cb, + final Predicate... additionalPredicates) { + final List predicates = new ArrayList<>(); + specifications.forEach(spec -> predicates.add(spec.toPredicate(root, query, cb))); + for (final Predicate predicate : additionalPredicates) { + predicates.add(predicate); + } + return predicates.toArray(new Predicate[predicates.size()]); + } + + @Override + public Long countSoftwareModuleByFilters(final String searchText, final SoftwareModuleType type) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + if (!Strings.isNullOrEmpty(searchText)) { + spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); + specList.add(spec); + } + + if (null != type) { + spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + } + + return countSwModuleByCriteriaAPI(specList); + } + + @Override + public Page findSoftwareModuleTypesAll(final Pageable pageable) { + return softwareModuleTypeRepository.findByDeleted(pageable, false); + } + + @Override + public Long countSoftwareModuleTypesAll() { + return softwareModuleTypeRepository.countByDeleted(false); + } + + @Override + public SoftwareModuleType findSoftwareModuleTypeByKey(final String key) { + return softwareModuleTypeRepository.findByKey(key); + } + + @Override + public SoftwareModuleType findSoftwareModuleTypeById(final Long id) { + return softwareModuleTypeRepository.findOne(id); + } + + @Override + public SoftwareModuleType findSoftwareModuleTypeByName(final String name) { + return softwareModuleTypeRepository.findByName(name); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModuleType createSoftwareModuleType(final SoftwareModuleType type) { + if (type.getId() != null) { + throw new EntityAlreadyExistsException("Given type contains an Id!"); + } + + return softwareModuleTypeRepository.save((JpaSoftwareModuleType) type); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteSoftwareModuleType(final SoftwareModuleType ty) { + final JpaSoftwareModuleType type = (JpaSoftwareModuleType) ty; + + if (softwareModuleRepository.countByType(type) > 0 + || distributionSetTypeRepository.countByElementsSmType(type) > 0) { + final JpaSoftwareModuleType toDelete = entityManager.merge(type); + toDelete.setDeleted(true); + softwareModuleTypeRepository.save(toDelete); + } else { + softwareModuleTypeRepository.delete(type.getId()); + } + } + + @Override + public Page findSoftwareModuleByAssignedTo(final Pageable pageable, final DistributionSet set) { + return softwareModuleRepository.findByAssignedTo(pageable, (JpaDistributionSet) set); + } + + @Override + public Page findSoftwareModuleByAssignedToAndType(final Pageable pageable, + final DistributionSet set, final SoftwareModuleType type) { + return softwareModuleRepository.findByAssignedToAndType(pageable, (JpaDistributionSet) set, + (JpaSoftwareModuleType) type); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public SoftwareModuleMetadata createSoftwareModuleMetadata(final SoftwareModuleMetadata md) { + final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) md; + + if (softwareModuleMetadataRepository.exists(metadata.getId())) { + throwMetadataKeyAlreadyExists(metadata.getId().getKey()); + } + // merge base software module so optLockRevision gets updated and audit + // log written because + // modifying metadata is modifying the base software module itself for + // auditing purposes. + entityManager.merge((JpaSoftwareModule) metadata.getSoftwareModule()).setLastModifiedAt(-1L); + return softwareModuleMetadataRepository.save(metadata); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public List createSoftwareModuleMetadata(final Collection md) { + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Collection metadata = (Collection) md; + + for (final JpaSoftwareModuleMetadata softwareModuleMetadata : metadata) { + checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(softwareModuleMetadata.getId()); + } + metadata.forEach(m -> entityManager.merge((JpaSoftwareModule) m.getSoftwareModule()).setLastModifiedAt(-1L)); + return new ArrayList<>(softwareModuleMetadataRepository.save(metadata)); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public SoftwareModuleMetadata updateSoftwareModuleMetadata(final SoftwareModuleMetadata md) { + final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) md; + + // check if exists otherwise throw entity not found exception + findSoftwareModuleMetadata(metadata.getId()); + // touch it to update the lock revision because we are modifying the + // software module + // indirectly + entityManager.merge((JpaSoftwareModule) metadata.getSoftwareModule()).setLastModifiedAt(-1L); + return softwareModuleMetadataRepository.save(metadata); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public void deleteSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key) { + softwareModuleMetadataRepository.delete(new SwMetadataCompositeKey(softwareModule, key)); + } + + @Override + public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long swId, + final Pageable pageable) { + return softwareModuleMetadataRepository.findBySoftwareModuleId(swId, pageable); + } + + @Override + public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId, + final String rsqlParam, final Pageable pageable) { + + final Specification spec = RSQLUtility.parse(rsqlParam, + SoftwareModuleMetadataFields.class); + return convertSmMdPage( + softwareModuleMetadataRepository + .findAll( + (Specification) (root, query, cb) -> cb.and( + cb.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule) + .get(JpaSoftwareModule_.id), softwareModuleId), + spec.toPredicate(root, query, cb)), + pageable), + pageable); + } + + @Override + public SoftwareModuleMetadata findSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key) { + return findSoftwareModuleMetadata(new SwMetadataCompositeKey(softwareModule, key)); + } + + private SoftwareModuleMetadata findSoftwareModuleMetadata(final SwMetadataCompositeKey id) { + final SoftwareModuleMetadata findOne = softwareModuleMetadataRepository.findOne(id); + if (findOne == null) { + throw new EntityNotFoundException("Metadata with key '" + id.getKey() + "' does not exist"); + } + return findOne; + } + + private void checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(final SwMetadataCompositeKey metadataId) { + if (softwareModuleMetadataRepository.exists(metadataId)) { + throw new EntityAlreadyExistsException( + "Metadata entry with key '" + metadataId.getKey() + "' already exists"); + } + } + + private static void throwMetadataKeyAlreadyExists(final String metadataKey) { + throw new EntityAlreadyExistsException("Metadata entry with key '" + metadataKey + "' already exists"); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteSoftwareModule(final SoftwareModule bsm) { + deleteSoftwareModules(Sets.newHashSet(bsm.getId())); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List createSoftwareModuleType(final Collection types) { + + return types.stream().map(this::createSoftwareModuleType).collect(Collectors.toList()); + } + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java similarity index 56% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java index 49c9183a7..3b7f77b47 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java @@ -6,48 +6,50 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; -import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.List; import java.util.stream.Collectors; import javax.persistence.EntityManager; -import javax.validation.constraints.NotNull; import org.eclipse.hawkbit.cache.TenancyCacheManager; -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.report.model.SystemUsageReport; +import org.eclipse.hawkbit.repository.Constants; +import org.eclipse.hawkbit.repository.SystemManagement; +import org.eclipse.hawkbit.repository.TenantStatsManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; +import org.eclipse.hawkbit.repository.jpa.model.JpaTenantMetaData; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.TenantMetaData; +import org.eclipse.hawkbit.repository.report.model.SystemUsageReport; +import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.persistence.config.PersistenceUnitProperties; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.interceptor.KeyGenerator; -import org.springframework.cache.interceptor.SimpleKeyGenerator; -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.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.DefaultTransactionDefinition; +import org.springframework.transaction.support.TransactionTemplate; import org.springframework.validation.annotation.Validated; /** - * Central system management operations of the SP server. + * JPA implementation of {@link SystemManagement}. * */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service -public class SystemManagement { +public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, SystemManagement { @Autowired private EntityManager entityManager; @@ -105,16 +107,16 @@ public class SystemManagement { @Autowired private TenancyCacheManager cacheManager; - private final ThreadLocal createInitialTenant = new ThreadLocal<>(); + @Autowired + private SystemManagementCacheKeyGenerator currentTenantCacheKeyGenerator; - /** - * Calculated system usage statistics, both overall for the entire system - * and per tenant; - * - * @return SystemUsageReport of the current system - */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN) + @Autowired + private SystemSecurityContext systemSecurityContext; + + @Autowired + private PlatformTransactionManager txManager; + + @Override public SystemUsageReport getSystemUsageStatistics() { BigDecimal sumOfArtifacts = (BigDecimal) entityManager @@ -151,80 +153,69 @@ public class SystemManagement { final List tenants = findTenants(); tenants.forEach(tenant -> tenantAware.runAsTenant(tenant, () -> { - report.addTenantData(systemStatsManagement.getStatsOfTenant(tenant)); + report.addTenantData(systemStatsManagement.getStatsOfTenant()); return null; })); } - /** - * Registers the key generator for the {@link #currentTenant()} method - * because this key generator is aware of the {@link #createInitialTenant} - * thread local in case we are currently creating a tenant and insert the - * default distribution set types. - * - * @return the {@link CurrentTenantKeyGenerator} - */ - @Bean + @Override @Transactional(propagation = Propagation.SUPPORTS) - public CurrentTenantKeyGenerator currentTenantKeyGenerator() { - return new CurrentTenantKeyGenerator(); + public KeyGenerator currentTenantKeyGenerator() { + return currentTenantCacheKeyGenerator.currentTenantKeyGenerator(); } - /** - * Returns {@link TenantMetaData} of given and current tenant. - * - * DISCLAIMER: this variant is used during initial login (where the tenant - * is not yet in the session). Please user {@link #getTenantMetadata()} for - * regular requests. - * - * @param tenant - * @return - */ - @Cacheable(value = "tenantMetadata", key = "#tenant.toUpperCase()") + @Override @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - @NotNull - public TenantMetaData getTenantMetadata(@NotNull final String tenant) { + public TenantMetaData getTenantMetadata(final String tenant) { final TenantMetaData result = tenantMetaDataRepository.findByTenantIgnoreCase(tenant); - // Create if it does not exist if (result == null) { try { - createInitialTenant.set(tenant); - cacheManager.getCache("currentTenant").evict(currentTenantKeyGenerator().generate(null, null)); - return tenantMetaDataRepository.save(new TenantMetaData(createStandardSoftwareDataSetup(), tenant)); + currentTenantCacheKeyGenerator.getCreateInitialTenant().set(tenant); + return createInitialTenantMetaData(tenant); + } finally { - createInitialTenant.remove(); + currentTenantCacheKeyGenerator.getCreateInitialTenant().remove(); } } - return result; } /** - * - * @return list of all tenant names in the system. + * Creating the initial tenant meta-data in a new transaction. Due the + * {@link MultiTenantJpaTransactionManager} is using the current tenant to + * set the necessary tenant discriminator to the query. This is not working + * if we don't have a current tenant set. Due the + * {@link #getTenantMetadata(String)} is maybe called without having a + * current tenant we need to re-open a new transaction so the + * {@link MultiTenantJpaTransactionManager} is called again and set the + * tenant for this transaction. + * + * @param tenant + * the tenant to be created + * @return the initial created {@link TenantMetaData} */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_SYSTEM_CODE) + private TenantMetaData createInitialTenantMetaData(final String tenant) { + final DefaultTransactionDefinition def = new DefaultTransactionDefinition(); + def.setName("initial-tenant-creation"); + def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + return systemSecurityContext.runAsSystemAsTenant( + () -> new TransactionTemplate(txManager, def).execute(status -> tenantMetaDataRepository + .save(new JpaTenantMetaData(createStandardSoftwareDataSetup(), tenant))), + tenant); + } + + @Override public List findTenants() { return tenantMetaDataRepository.findAll().stream().map(md -> md.getTenant()).collect(Collectors.toList()); } - /** - * Deletes all data related to a given tenant. - * - * @param tenant - * to delete - */ - @CacheEvict(value = { "tenantMetadata" }, key = "#tenant.toUpperCase()") + @Override @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN) - public void deleteTenant(@NotNull final String tenant) { + public void deleteTenant(final String tenant) { cacheManager.evictCaches(tenant); - cacheManager.getCache("currentTenant").evict(currentTenantKeyGenerator().generate(null, null)); tenantAware.runAsTenant(tenant, () -> { entityManager.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, tenant.toUpperCase()); tenantMetaDataRepository.deleteByTenantIgnoreCase(tenant); @@ -246,13 +237,9 @@ public class SystemManagement { }); } - /** - * @return {@link TenantMetaData} of {@link TenantAware#getCurrentTenant()} - */ - @Cacheable(value = "tenantMetadata", keyGenerator = "tenantKeyGenerator") + @Override @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - @NotNull public TenantMetaData getTenantMetadata() { if (tenantAware.getCurrentTenant() == null) { throw new IllegalStateException("Tenant not set"); @@ -261,14 +248,8 @@ public class SystemManagement { return getTenantMetadata(tenantAware.getCurrentTenant()); } - /** - * Checks if a specific tenant exists. The tenant will not be created lazy. - * - * @param tenant - * the tenant to check - * @return {@code true} in case the tenant exits or {@code false} if not - */ - @Cacheable(value = "currentTenant", keyGenerator = "currentTenantKeyGenerator") + @Override + @Cacheable(value = "currentTenant", keyGenerator = "currentTenantKeyGenerator", cacheManager = "directCacheManager") // set transaction to not supported, due we call this in // BaseEntity#prePersist methods // and it seems that JPA committing the transaction when executing this @@ -281,7 +262,7 @@ public class SystemManagement { // tenant is not cached anyway already. @Transactional(propagation = Propagation.NOT_SUPPORTED, isolation = Isolation.READ_UNCOMMITTED) public String currentTenant() { - final String initialTenantCreation = createInitialTenant.get(); + final String initialTenantCreation = currentTenantCacheKeyGenerator.getCreateInitialTenant().get(); if (initialTenantCreation == null) { final TenantMetaData findByTenant = tenantMetaDataRepository .findByTenantIgnoreCase(tenantAware.getCurrentTenant()); @@ -290,68 +271,32 @@ public class SystemManagement { return initialTenantCreation; } - /** - * Update call for {@link TenantMetaData}. - * - * @param metaData - * to update - * @return updated {@link TenantMetaData} entity - */ - @CachePut(value = "tenantMetadata", key = "#metaData.tenant.toUpperCase()") + @Override @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - @NotNull - public TenantMetaData updateTenantMetadata(@NotNull final TenantMetaData metaData) { + public TenantMetaData updateTenantMetadata(final TenantMetaData metaData) { if (!tenantMetaDataRepository.exists(metaData.getId())) { throw new EntityNotFoundException("Metadata does not exist: " + metaData.getId()); } - return tenantMetaDataRepository.save(metaData); + return tenantMetaDataRepository.save((JpaTenantMetaData) metaData); } private DistributionSetType createStandardSoftwareDataSetup() { - final SoftwareModuleType eclApp = softwareModuleTypeRepository.save(new SoftwareModuleType("application", - "ECL Application", "Edge Controller Linux base application type", 1)); - final SoftwareModuleType eclOs = softwareModuleTypeRepository - .save(new SoftwareModuleType("os", "ECL OS", "Edge Controller Linux operation system image type", 1)); - final SoftwareModuleType eclJvm = softwareModuleTypeRepository.save( - new SoftwareModuleType("runtime", "ECL JVM", "Edge Controller Linux java virtual machine type.", 1)); + final SoftwareModuleType app = softwareModuleTypeRepository + .save(new JpaSoftwareModuleType(Constants.SMT_DEFAULT_APP_KEY, Constants.SMT_DEFAULT_APP_NAME, + "Application Addons", Integer.MAX_VALUE)); + final SoftwareModuleType os = softwareModuleTypeRepository.save(new JpaSoftwareModuleType( + Constants.SMT_DEFAULT_OS_KEY, Constants.SMT_DEFAULT_OS_NAME, "Core firmware or operationg system", 1)); - distributionSetTypeRepository.save( - new DistributionSetType("ecl_os", "OS only", "Standard Edge Controller Linux distribution set type.") - .addMandatoryModuleType(eclOs)); - - distributionSetTypeRepository.save(new DistributionSetType("ecl_os_app", "OS with optional app", - "Standard Edge Controller Linux distribution set type. OS only.").addMandatoryModuleType(eclOs) - .addOptionalModuleType(eclApp)); + distributionSetTypeRepository + .save((JpaDistributionSetType) new JpaDistributionSetType(Constants.DST_DEFAULT_OS_ONLY_KEY, + Constants.DST_DEFAULT_OS_ONLY_NAME, "Default type with Firmware/OS only.") + .addMandatoryModuleType(os)); return distributionSetTypeRepository - .save(new DistributionSetType("ecl_os_app_jvm", "OS with optional app and jvm", - "Standard Edge Controller Linux distribution set type. OS with optional application.") - .addMandatoryModuleType(eclOs).addOptionalModuleType(eclApp) - .addOptionalModuleType(eclJvm)); + .save((JpaDistributionSetType) new JpaDistributionSetType(Constants.DST_DEFAULT_OS_WITH_APPS_KEY, + Constants.DST_DEFAULT_OS_WITH_APPS_NAME, "Default type with Firmware/OS and optional app(s).") + .addMandatoryModuleType(os).addOptionalModuleType(app)); } - - /** - * A implementation of the {@link KeyGenerator} to generate a key based on - * either the {@code createInitialTenant} thread local and the - * {@link TenantAware}, but in case we are in a tenant creation with its - * default types we need to use the tenant the current tenant which is - * currently created and not the one currently in the {@link TenantAware}. - * - */ - 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) { - return SimpleKeyGenerator.generateKey(tenantAware.getCurrentTenant().toUpperCase(), - tenantAware.getCurrentTenant().toUpperCase()); - } - return SimpleKeyGenerator.generateKey(initialTenantCreation.toUpperCase(), - initialTenantCreation.toUpperCase()); - } - } -} +} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java new file mode 100644 index 000000000..e881d8ef8 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java @@ -0,0 +1,287 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.hawkbit.repository.TagFields; +import org.eclipse.hawkbit.repository.TagManagement; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagCreatedBulkEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetTagCreatedBulkEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetTagDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetTagUpdateEvent; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; +import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.TargetTag; +import org.eclipse.hawkbit.tenancy.TenantAware; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import com.google.common.eventbus.EventBus; + +/** + * JP>A implementation of {@link TagManagement}. + * + */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) +@Validated +public class JpaTagManagement implements TagManagement { + + @Autowired + private TargetTagRepository targetTagRepository; + + @Autowired + private TargetRepository targetRepository; + + @Autowired + private DistributionSetTagRepository distributionSetTagRepository; + + @Autowired + private DistributionSetRepository distributionSetRepository; + + @Autowired + private EventBus eventBus; + + @Autowired + private TenantAware tenantAware; + + @Autowired + private AfterTransactionCommitExecutor afterCommit; + + @Override + public TargetTag findTargetTag(final String name) { + return targetTagRepository.findByNameEquals(name); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public TargetTag createTargetTag(final TargetTag targetTag) { + if (null != targetTag.getId()) { + throw new EntityAlreadyExistsException(); + } + + if (findTargetTag(targetTag.getName()) != null) { + throw new EntityAlreadyExistsException(); + } + + final TargetTag save = targetTagRepository.save((JpaTargetTag) targetTag); + + afterCommit + .afterCommit(() -> eventBus.post(new TargetTagCreatedBulkEvent(tenantAware.getCurrentTenant(), save))); + + return save; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List createTargetTags(final Collection tt) { + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Collection targetTags = (Collection) tt; + + targetTags.forEach(tag -> { + if (tag.getId() != null) { + throw new EntityAlreadyExistsException(); + } + }); + + final List save = new ArrayList<>(targetTagRepository.save(targetTags)); + afterCommit + .afterCommit(() -> eventBus.post(new TargetTagCreatedBulkEvent(tenantAware.getCurrentTenant(), save))); + return save; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteTargetTag(final String targetTagName) { + final JpaTargetTag tag = targetTagRepository.findByNameEquals(targetTagName); + + final List changed = new LinkedList<>(); + for (final JpaTarget target : targetRepository.findByTag(tag)) { + target.getTags().remove(tag); + changed.add(target); + } + + // save association delete + targetRepository.save(changed); + + // finally delete the tag itself + targetTagRepository.deleteByName(targetTagName); + + afterCommit.afterCommit(() -> eventBus.post(new TargetTagDeletedEvent(tag))); + + } + + @Override + public List findAllTargetTags() { + return new ArrayList<>(targetTagRepository.findAll()); + } + + @Override + public Page findAllTargetTags(final String rsqlParam, final Pageable pageable) { + + final Specification spec = RSQLUtility.parse(rsqlParam, TagFields.class); + return convertTPage(targetTagRepository.findAll(spec, pageable), pageable); + } + + private static Page convertTPage(final Page findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + private static Page convertDsPage(final Page findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + public long countTargetTags() { + return targetTagRepository.count(); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public TargetTag updateTargetTag(final TargetTag targetTag) { + checkNotNull(targetTag.getName()); + checkNotNull(targetTag.getId()); + final TargetTag save = targetTagRepository.save((JpaTargetTag) targetTag); + afterCommit.afterCommit(() -> eventBus.post(new TargetTagUpdateEvent(save))); + return save; + } + + @Override + public DistributionSetTag findDistributionSetTag(final String name) { + return distributionSetTagRepository.findByNameEquals(name); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public DistributionSetTag createDistributionSetTag(final DistributionSetTag distributionSetTag) { + if (null != distributionSetTag.getId()) { + throw new EntityAlreadyExistsException(); + } + + if (distributionSetTagRepository.findByNameEquals(distributionSetTag.getName()) != null) { + throw new EntityAlreadyExistsException(); + } + + final DistributionSetTag save = distributionSetTagRepository.save((JpaDistributionSetTag) distributionSetTag); + + afterCommit.afterCommit( + () -> eventBus.post(new DistributionSetTagCreatedBulkEvent(tenantAware.getCurrentTenant(), save))); + return save; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List createDistributionSetTags(final Collection dst) { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + final Collection distributionSetTags = (Collection) dst; + + for (final DistributionSetTag dsTag : distributionSetTags) { + if (dsTag.getId() != null) { + throw new EntityAlreadyExistsException(); + } + } + final List save = new ArrayList<>(distributionSetTagRepository.save(distributionSetTags)); + afterCommit.afterCommit( + () -> eventBus.post(new DistributionSetTagCreatedBulkEvent(tenantAware.getCurrentTenant(), save))); + + return save; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteDistributionSetTag(final String tagName) { + final JpaDistributionSetTag tag = distributionSetTagRepository.findByNameEquals(tagName); + + final List changed = new LinkedList<>(); + for (final JpaDistributionSet set : distributionSetRepository.findByTag(tag)) { + set.getTags().remove(tag); + changed.add(set); + } + + // save association delete + distributionSetRepository.save(changed); + + distributionSetTagRepository.deleteByName(tagName); + + afterCommit.afterCommit(() -> eventBus.post(new DistributionSetTagDeletedEvent(tag))); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public DistributionSetTag updateDistributionSetTag(final DistributionSetTag distributionSetTag) { + checkNotNull(distributionSetTag.getName()); + checkNotNull(distributionSetTag.getId()); + final DistributionSetTag save = distributionSetTagRepository.save((JpaDistributionSetTag) distributionSetTag); + afterCommit.afterCommit(() -> eventBus.post(new DistributionSetTagUpdateEvent(save))); + + return save; + } + + @Override + public List findAllDistributionSetTags() { + return new ArrayList<>(distributionSetTagRepository.findAll()); + } + + @Override + public TargetTag findTargetTagById(final Long id) { + return targetTagRepository.findOne(id); + } + + @Override + public DistributionSetTag findDistributionSetTagById(final Long id) { + return distributionSetTagRepository.findOne(id); + } + + @Override + public Page findAllTargetTags(final Pageable pageable) { + return convertTPage(targetTagRepository.findAll(pageable), pageable); + } + + @Override + public Page findAllDistributionSetTags(final Pageable pageable) { + return convertDsPage(distributionSetTagRepository.findAll(pageable), pageable); + } + + @Override + public Page findAllDistributionSetTags(final String rsqlParam, final Pageable pageable) { + final Specification spec = RSQLUtility.parse(rsqlParam, TagFields.class); + + return convertDsPage(distributionSetTagRepository.findAll(spec, pageable), pageable); + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java new file mode 100644 index 000000000..65ed6faa4 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java @@ -0,0 +1,119 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.hawkbit.repository.TargetFields; +import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; +import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; +import org.eclipse.hawkbit.repository.jpa.specifications.TargetFilterQuerySpecification; +import org.eclipse.hawkbit.repository.model.TargetFilterQuery; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.domain.Specifications; +import org.springframework.data.jpa.repository.Modifying; +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; + +import com.google.common.base.Strings; + +/** + * JPA implementation of {@link TargetFilterQueryManagement}. + * + */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) +@Validated +public class JpaTargetFilterQueryManagement implements TargetFilterQueryManagement { + + @Autowired + private TargetFilterQueryRepository targetFilterQueryRepository; + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public TargetFilterQuery createTargetFilterQuery(final TargetFilterQuery customTargetFilter) { + + if (targetFilterQueryRepository.findByName(customTargetFilter.getName()) != null) { + throw new EntityAlreadyExistsException(customTargetFilter.getName()); + } + return targetFilterQueryRepository.save((JpaTargetFilterQuery) customTargetFilter); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteTargetFilterQuery(final Long targetFilterQueryId) { + targetFilterQueryRepository.delete(targetFilterQueryId); + } + + @Override + public Page findAllTargetFilterQuery(final Pageable pageable) { + return convertPage(targetFilterQueryRepository.findAll(pageable), pageable); + } + + private static Page convertPage(final Page findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + public Page findTargetFilterQueryByFilters(final Pageable pageable, final String name) { + final List> specList = new ArrayList<>(); + if (!Strings.isNullOrEmpty(name)) { + specList.add(TargetFilterQuerySpecification.likeName(name)); + } + return convertPage(findTargetFilterQueryByCriteriaAPI(pageable, specList), pageable); + } + + private Page findTargetFilterQueryByCriteriaAPI(final Pageable pageable, + final List> specList) { + if (specList == null || specList.isEmpty()) { + return targetFilterQueryRepository.findAll(pageable); + } + + final Specifications specs = SpecificationsBuilder.combineWithAnd(specList); + return targetFilterQueryRepository.findAll(specs, pageable); + } + + @Override + public TargetFilterQuery findTargetFilterQueryByName(final String targetFilterQueryName) { + return targetFilterQueryRepository.findByName(targetFilterQueryName); + } + + @Override + public TargetFilterQuery findTargetFilterQueryById(final Long targetFilterQueryId) { + return targetFilterQueryRepository.findOne(targetFilterQueryId); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public TargetFilterQuery updateTargetFilterQuery(final TargetFilterQuery targetFilterQuery) { + Assert.notNull(targetFilterQuery.getId()); + return targetFilterQueryRepository.save((JpaTargetFilterQuery) targetFilterQuery); + } + + @Override + public boolean verifyTargetFilterQuerySyntax(final String query) { + RSQLUtility.parse(query, TargetFields.class); + return true; + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java new file mode 100644 index 000000000..1cd2ffc3c --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -0,0 +1,655 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import javax.annotation.PreDestroy; +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.Order; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import org.eclipse.hawkbit.repository.TargetFields; +import org.eclipse.hawkbit.repository.TargetManagement; +import org.eclipse.hawkbit.repository.eventbus.event.TargetTagAssigmentResultEvent; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.jpa.configuration.Constants; +import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; +import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; +import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetFilterQuery; +import org.eclipse.hawkbit.repository.model.TargetIdName; +import org.eclipse.hawkbit.repository.model.TargetTag; +import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.validation.annotation.Validated; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.common.eventbus.EventBus; + +/** + * JPA implementation of {@link TargetManagement}. + * + */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) +@Validated +public class JpaTargetManagement implements TargetManagement { + + @Autowired + private EntityManager entityManager; + + @Autowired + private TargetRepository targetRepository; + + @Autowired + private TargetTagRepository targetTagRepository; + + @Autowired + private TargetInfoRepository targetInfoRepository; + + @Autowired + private NoCountPagingRepository criteriaNoCountDao; + + @Autowired + private EventBus eventBus; + + @Autowired + private AfterTransactionCommitExecutor afterCommit; + + @Override + public Target findTargetByControllerID(final String controllerId) { + return targetRepository.findByControllerId(controllerId); + } + + @Override + public Target findTargetByControllerIDWithDetails(final String controllerId) { + final Target result = targetRepository.findByControllerId(controllerId); + // load lazy relations + if (result != null) { + result.getTargetInfo().getControllerAttributes().size(); + if (result.getTargetInfo() != null && result.getTargetInfo().getInstalledDistributionSet() != null) { + result.getTargetInfo().getInstalledDistributionSet().getName(); + result.getTargetInfo().getInstalledDistributionSet().getModules().size(); + } + if (result.getAssignedDistributionSet() != null) { + result.getAssignedDistributionSet().getName(); + result.getAssignedDistributionSet().getModules().size(); + } + } + return result; + } + + @Override + public List findTargetByControllerID(final Collection controllerIDs) { + return new ArrayList<>(targetRepository + .findAll(TargetSpecifications.byControllerIdWithStatusAndAssignedInJoin(controllerIDs))); + } + + @Override + public Long countTargetsAll() { + return targetRepository.count(); + } + + @Override + public Slice findTargetsAll(final Pageable pageable) { + // workarround - no join fetch allowed that is why we need specification + // instead of query for + // count() of Pageable + final Specification spec = (root, query, cb) -> { + if (!query.getResultType().isAssignableFrom(Long.class)) { + root.fetch(JpaTarget_.targetInfo); + } + return cb.conjunction(); + }; + return convertPage(criteriaNoCountDao.findAll(spec, pageable, JpaTarget.class), pageable); + } + + @Override + public Slice findTargetsAll(final TargetFilterQuery targetFilterQuery, final Pageable pageable) { + return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class), pageable); + } + + @Override + public Page findTargetsAll(final String targetFilterQuery, final Pageable pageable) { + return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery, TargetFields.class), pageable); + } + + private Page findTargetsBySpec(final Specification spec, final Pageable pageable) { + return convertPage(targetRepository.findAll(spec, pageable), pageable); + } + + @Override + public List findTargetsByControllerIDsWithTags(final List controllerIDs) { + final List> partition = Lists.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT); + return partition.stream() + .map(ids -> targetRepository.findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(ids))) + .flatMap(t -> t.stream()).collect(Collectors.toList()); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public Target updateTarget(final Target target) { + Assert.notNull(target.getId()); + + final JpaTarget toUpdate = (JpaTarget) target; + toUpdate.setNew(false); + return targetRepository.save(toUpdate); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List updateTargets(final Collection targets) { + + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Collection toUpdate = (Collection) targets; + + toUpdate.forEach(target -> target.setNew(false)); + + return new ArrayList<>(targetRepository.save(toUpdate)); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteTargets(final Long... targetIDs) { + // we need to select the target IDs first to check the if the targetIDs + // belonging to the + // tenant! Delete statement are not automatically enhanced with the + // @FilterDef of the + // hibernate session. + final List targetsForCurrentTenant = targetRepository.findAll(Lists.newArrayList(targetIDs)).stream() + .map(Target::getId).collect(Collectors.toList()); + if (!targetsForCurrentTenant.isEmpty()) { + targetInfoRepository.deleteByTargetIdIn(targetsForCurrentTenant); + targetRepository.deleteByIdIn(targetsForCurrentTenant); + } + } + + @Override + public Page findTargetByAssignedDistributionSet(final Long distributionSetID, final Pageable pageReq) { + return targetRepository.findByAssignedDistributionSetId(pageReq, distributionSetID); + } + + @Override + public Page findTargetByAssignedDistributionSet(final Long distributionSetID, final String rsqlParam, + final Pageable pageReq) { + + final Specification spec = RSQLUtility.parse(rsqlParam, TargetFields.class); + + return convertPage( + targetRepository + .findAll((Specification) (root, query, + cb) -> cb.and(TargetSpecifications.hasAssignedDistributionSet(distributionSetID) + .toPredicate(root, query, cb), spec.toPredicate(root, query, cb)), + pageReq), + pageReq); + } + + private static Page convertPage(final Page findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + private static Slice convertPage(final Slice findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, 0); + } + + @Override + public Page findTargetByInstalledDistributionSet(final Long distributionSetID, final Pageable pageReq) { + return targetRepository.findByTargetInfoInstalledDistributionSetId(pageReq, distributionSetID); + } + + @Override + public Page findTargetByInstalledDistributionSet(final Long distributionSetId, final String rsqlParam, + final Pageable pageable) { + + final Specification spec = RSQLUtility.parse(rsqlParam, TargetFields.class); + + return convertPage( + targetRepository + .findAll((Specification) (root, query, + cb) -> cb.and(TargetSpecifications.hasInstalledDistributionSet(distributionSetId) + .toPredicate(root, query, cb), spec.toPredicate(root, query, cb)), + pageable), + pageable); + } + + @Override + public Page findTargetByUpdateStatus(final Pageable pageable, final TargetUpdateStatus status) { + return targetRepository.findByTargetInfoUpdateStatus(pageable, status); + } + + @Override + public Slice findTargetByFilters(final Pageable pageable, final Collection status, + final String searchText, final Long installedOrAssignedDistributionSetId, + final Boolean selectTargetWithNoTag, final String... tagNames) { + final List> specList = buildSpecificationList(status, searchText, + installedOrAssignedDistributionSetId, selectTargetWithNoTag, true, tagNames); + return findByCriteriaAPI(pageable, specList); + } + + @Override + public Long countTargetByFilters(final Collection status, final String searchText, + final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag, + final String... tagNames) { + final List> specList = buildSpecificationList(status, searchText, + installedOrAssignedDistributionSetId, selectTargetWithNoTag, true, tagNames); + return countByCriteriaAPI(specList); + } + + private static List> buildSpecificationList(final Collection status, + final String searchText, final Long installedOrAssignedDistributionSetId, + final Boolean selectTargetWithNoTag, final boolean fetch, final String... tagNames) { + final List> specList = new ArrayList<>(); + if (status != null && !status.isEmpty()) { + specList.add(TargetSpecifications.hasTargetUpdateStatus(status, fetch)); + } + if (installedOrAssignedDistributionSetId != null) { + specList.add( + TargetSpecifications.hasInstalledOrAssignedDistributionSet(installedOrAssignedDistributionSetId)); + } + if (!Strings.isNullOrEmpty(searchText)) { + specList.add(TargetSpecifications.likeNameOrDescriptionOrIp(searchText)); + } + if (selectTargetWithNoTag != null && (selectTargetWithNoTag || (tagNames != null && tagNames.length > 0))) { + specList.add(TargetSpecifications.hasTags(tagNames, selectTargetWithNoTag)); + } + return specList; + } + + private Slice findByCriteriaAPI(final Pageable pageable, final List> specList) { + if (specList == null || specList.isEmpty()) { + return convertPage(criteriaNoCountDao.findAll(pageable, JpaTarget.class), pageable); + } + return convertPage( + criteriaNoCountDao.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable, JpaTarget.class), + pageable); + } + + private Long countByCriteriaAPI(final List> specList) { + if (specList == null || specList.isEmpty()) { + return targetRepository.count(); + } + + return targetRepository.count(SpecificationsBuilder.combineWithAnd(specList)); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public TargetTagAssignmentResult toggleTagAssignment(final Collection targets, final TargetTag tag) { + return toggleTagAssignment( + targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()), tag.getName()); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public TargetTagAssignmentResult toggleTagAssignment(final Collection targetIds, final String tagName) { + final TargetTag tag = targetTagRepository.findByNameEquals(tagName); + final List alreadyAssignedTargets = targetRepository.findByTagNameAndControllerIdIn(tagName, targetIds); + final List allTargets = targetRepository + .findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(targetIds)); + + // all are already assigned -> unassign + if (alreadyAssignedTargets.size() == allTargets.size()) { + alreadyAssignedTargets.forEach(target -> target.getTags().remove(tag)); + final TargetTagAssignmentResult result = new TargetTagAssignmentResult(0, 0, alreadyAssignedTargets.size(), + Collections.emptyList(), alreadyAssignedTargets, tag); + + afterCommit.afterCommit(() -> eventBus.post(new TargetTagAssigmentResultEvent(result))); + return result; + } + + allTargets.removeAll(alreadyAssignedTargets); + // some or none are assigned -> assign + allTargets.forEach(target -> target.getTags().add(tag)); + final TargetTagAssignmentResult result = new TargetTagAssignmentResult(alreadyAssignedTargets.size(), + allTargets.size(), 0, new ArrayList<>(targetRepository.save(allTargets)), Collections.emptyList(), tag); + + afterCommit.afterCommit(() -> eventBus.post(new TargetTagAssigmentResultEvent(result))); + + // no reason to persist the tag + entityManager.detach(tag); + return result; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List assignTag(final Collection targetIds, final TargetTag tag) { + final List allTargets = targetRepository + .findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(targetIds)); + + allTargets.forEach(target -> target.getTags().add(tag)); + final List save = new ArrayList<>(targetRepository.save(allTargets)); + + afterCommit.afterCommit(() -> { + final TargetTagAssignmentResult assigmentResult = new TargetTagAssignmentResult(0, save.size(), 0, save, + Collections.emptyList(), tag); + eventBus.post(new TargetTagAssigmentResultEvent(assigmentResult)); + }); + + return save; + } + + private List unAssignTag(final Collection targets, final TargetTag tag) { + final Collection toUnassign = (Collection) targets; + + toUnassign.forEach(target -> target.getTags().remove(tag)); + + final List save = new ArrayList<>(targetRepository.save(toUnassign)); + afterCommit.afterCommit(() -> { + final TargetTagAssignmentResult assigmentResult = new TargetTagAssignmentResult(0, 0, save.size(), + Collections.emptyList(), save, tag); + eventBus.post(new TargetTagAssigmentResultEvent(assigmentResult)); + }); + return save; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List unAssignAllTargetsByTag(final TargetTag tag) { + return unAssignTag(tag.getAssignedToTargets(), tag); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public Target unAssignTag(final String controllerID, final TargetTag targetTag) { + final List allTargets = new ArrayList<>(targetRepository + .findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(Arrays.asList(controllerID)))); + final List unAssignTag = unAssignTag(allTargets, targetTag); + return unAssignTag.isEmpty() ? null : unAssignTag.get(0); + } + + @Override + public Slice findTargetsAllOrderByLinkedDistributionSet(final Pageable pageable, + final Long orderByDistributionId, final Long filterByDistributionId, + final Collection filterByStatus, final String filterBySearchText, + final Boolean selectTargetWithNoTag, final String... filterByTagNames) { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery query = cb.createQuery(JpaTarget.class); + final Root targetRoot = query.from(JpaTarget.class); + + // necessary joins for the select + final Join targetInfo = (Join) targetRoot + .fetch(JpaTarget_.targetInfo, JoinType.LEFT); + + // select case expression to retrieve the case value as a column to be + // able to order based on + // this column, installed first,... + final Expression selectCase = cb.selectCase() + .when(cb.equal(targetInfo.get(JpaTargetInfo_.installedDistributionSet).get(JpaDistributionSet_.id), + orderByDistributionId), 1) + .when(cb.equal(targetRoot.get(JpaTarget_.assignedDistributionSet).get(JpaDistributionSet_.id), + orderByDistributionId), 2) + .otherwise(100); + // multiselect statement order by the select case and controllerId + query.distinct(true); + // build the specifications and then to predicates necessary by the + // given filters + final Predicate[] specificationsForMultiSelect = specificationsToPredicate( + buildSpecificationList(filterByStatus, filterBySearchText, filterByDistributionId, + selectTargetWithNoTag, true, filterByTagNames), + targetRoot, query, cb); + + // if we have some predicates then add it to the where clause of the + // multiselect + if (specificationsForMultiSelect.length > 0) { + query.where(specificationsForMultiSelect); + } + // add the order to the multi select first based on the selectCase + query.orderBy(cb.asc(selectCase), cb.desc(targetRoot.get(JpaTarget_.id))); + // the result is a Object[] due the fact that the selectCase is an extra + // column, so it cannot + // be mapped directly to a Target entity because the selectCase is not a + // attribute of the + // Target entity, the the Object array contains the Target on the first + // index (case of the + // multiselect order) of the array and + // the 2nd contains the selectCase int value. + final int pageSize = pageable.getPageSize(); + final List resultList = entityManager.createQuery(query).setFirstResult(pageable.getOffset()) + .setMaxResults(pageSize + 1).getResultList(); + final boolean hasNext = resultList.size() > pageSize; + return new SliceImpl<>(new ArrayList<>(resultList), pageable, hasNext); + } + + private static Predicate[] specificationsToPredicate(final List> specifications, + final Root root, final CriteriaQuery query, final CriteriaBuilder cb) { + final Predicate[] predicates = new Predicate[specifications.size()]; + for (int index = 0; index < predicates.length; index++) { + predicates[index] = specifications.get(index).toPredicate(root, query, cb); + } + return predicates; + } + + @Override + public Long countTargetByAssignedDistributionSet(final Long distId) { + return targetRepository.countByAssignedDistributionSetId(distId); + } + + @Override + public Long countTargetByInstalledDistributionSet(final Long distId) { + return targetRepository.countByTargetInfoInstalledDistributionSetId(distId); + } + + @Override + public List findAllTargetIds() { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery query = cb.createQuery(TargetIdName.class); + final Root targetRoot = query.from(JpaTarget.class); + return entityManager.createQuery(query.multiselect(targetRoot.get(JpaTarget_.id), + targetRoot.get(JpaTarget_.controllerId), targetRoot.get(JpaTarget_.name))).getResultList(); + + } + + @Override + public List findAllTargetIdsByFilters(final Pageable pageRequest, + final Collection filterByStatus, final String filterBySearchText, + final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag, + final String... filterByTagNames) { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery query = cb.createQuery(Object[].class); + final Root targetRoot = query.from(JpaTarget.class); + List resultList; + + String sortProperty = JpaTarget_.id.getName(); + if (pageRequest.getSort() != null && pageRequest.getSort().iterator().hasNext()) { + sortProperty = pageRequest.getSort().iterator().next().getProperty(); + } + + final CriteriaQuery multiselect = query.multiselect(targetRoot.get(JpaTarget_.id), + targetRoot.get(JpaTarget_.controllerId), targetRoot.get(JpaTarget_.name), targetRoot.get(sortProperty)); + + final Predicate[] specificationsForMultiSelect = specificationsToPredicate( + buildSpecificationList(filterByStatus, filterBySearchText, installedOrAssignedDistributionSetId, + selectTargetWithNoTag, false, filterByTagNames), + targetRoot, multiselect, cb); + + // if we have some predicates then add it to the where clause of the + // multiselect + if (specificationsForMultiSelect.length > 0) { + multiselect.where(specificationsForMultiSelect); + } + + resultList = getTargetIdNameResultSet(pageRequest, cb, targetRoot, multiselect); + return resultList.parallelStream().map(o -> new TargetIdName((long) o[0], o[1].toString(), o[2].toString())) + .collect(Collectors.toList()); + } + + @Override + public List findAllTargetIdsByTargetFilterQuery(final Pageable pageRequest, + final TargetFilterQuery targetFilterQuery) { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery query = cb.createQuery(Object[].class); + final Root targetRoot = query.from(JpaTarget.class); + + String sortProperty = JpaTarget_.id.getName(); + if (pageRequest.getSort() != null && pageRequest.getSort().iterator().hasNext()) { + sortProperty = pageRequest.getSort().iterator().next().getProperty(); + } + + final CriteriaQuery multiselect = query.multiselect(targetRoot.get(JpaTarget_.id), + targetRoot.get(JpaTarget_.controllerId), targetRoot.get(JpaTarget_.name), targetRoot.get(sortProperty)); + + final Specification spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class); + final List> specList = new ArrayList<>(); + specList.add(spec); + + final Predicate[] specificationsForMultiSelect = specificationsToPredicate(specList, targetRoot, multiselect, + cb); + + // if we have some predicates then add it to the where clause of the + // multiselect + if (specificationsForMultiSelect.length > 0) { + multiselect.where(specificationsForMultiSelect); + } + final List resultList = getTargetIdNameResultSet(pageRequest, cb, targetRoot, multiselect); + return resultList.parallelStream().map(o -> new TargetIdName((long) o[0], o[1].toString(), o[2].toString())) + .collect(Collectors.toList()); + } + + @PreDestroy + void destroy() { + eventBus.unregister(this); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @CacheEvict(value = { "targetsCreatedOverPeriod" }, allEntries = true) + public Target createTarget(final Target t, final TargetUpdateStatus status, final Long lastTargetQuery, + final URI address) { + final JpaTarget target = (JpaTarget) t; + + if (targetRepository.findByControllerId(target.getControllerId()) != null) { + throw new EntityAlreadyExistsException(target.getControllerId()); + } + + target.setNew(true); + final JpaTarget savedTarget = targetRepository.save(target); + final JpaTargetInfo targetInfo = (JpaTargetInfo) savedTarget.getTargetInfo(); + targetInfo.setUpdateStatus(status); + if (lastTargetQuery != null) { + targetInfo.setLastTargetQuery(lastTargetQuery); + } + if (address != null) { + targetInfo.setAddress(address.toString()); + } + targetInfo.setNew(true); + final Target targetToReturn = targetInfoRepository.save(targetInfo).getTarget(); + targetInfo.setNew(false); + return targetToReturn; + + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @CacheEvict(value = { "targetsCreatedOverPeriod" }, allEntries = true) + public Target createTarget(final Target target) { + return createTarget(target, TargetUpdateStatus.UNKNOWN, null, null); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List createTargets(final Collection targets) { + if (!targets.isEmpty() && targetRepository.countByControllerIdIn( + targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList())) > 0) { + throw new EntityAlreadyExistsException(); + } + final List savedTargets = new ArrayList<>(); + for (final Target t : targets) { + final Target myTarget = createTarget(t, TargetUpdateStatus.UNKNOWN, null, t.getTargetInfo().getAddress()); + savedTargets.add(myTarget); + } + return savedTargets; + } + + @Override + public List findTargetsByTag(final String tagName) { + final JpaTargetTag tag = targetTagRepository.findByNameEquals(tagName); + return new ArrayList<>(targetRepository.findByTag(tag)); + } + + @Override + public Long countTargetByTargetFilterQuery(final TargetFilterQuery targetFilterQuery) { + final Specification specs = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class); + return targetRepository.count(specs); + } + + @Override + public Long countTargetByTargetFilterQuery(final String targetFilterQuery) { + final Specification specs = RSQLUtility.parse(targetFilterQuery, TargetFields.class); + return targetRepository.count(specs); + } + + private List getTargetIdNameResultSet(final Pageable pageRequest, final CriteriaBuilder cb, + final Root targetRoot, final CriteriaQuery multiselect) { + List resultList; + if (pageRequest.getSort() != null) { + final List orders = new ArrayList<>(); + final Sort sort = pageRequest.getSort(); + for (final Sort.Order sortOrder : sort) { + if (sortOrder.getDirection() == Direction.ASC) { + orders.add(cb.asc(targetRoot.get(sortOrder.getProperty()))); + } else { + orders.add(cb.desc(targetRoot.get(sortOrder.getProperty()))); + } + } + multiselect.orderBy(orders); + resultList = entityManager.createQuery(multiselect).setFirstResult(pageRequest.getOffset()) + .setMaxResults(pageRequest.getPageSize()).getResultList(); + } else { + resultList = entityManager.createQuery(multiselect).getResultList(); + } + return resultList; + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantConfigurationManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantConfigurationManagement.java new file mode 100644 index 000000000..d5d6a5540 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantConfigurationManagement.java @@ -0,0 +1,170 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.jpa.model.JpaTenantConfiguration; +import org.eclipse.hawkbit.repository.model.TenantConfiguration; +import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidatorException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.ApplicationContext; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.convert.support.ConfigurableConversionService; +import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.Modifying; +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, isolation = Isolation.READ_UNCOMMITTED) +@Validated +public class JpaTenantConfigurationManagement implements EnvironmentAware, TenantConfigurationManagement { + + @Autowired + private TenantConfigurationRepository tenantConfigurationRepository; + + @Autowired + private ApplicationContext applicationContext; + + private static final ConfigurableConversionService conversionService = new DefaultConversionService(); + + private Environment environment; + + @Override + @Cacheable(value = "tenantConfiguration", key = "#configurationKey.getKeyName()") + public TenantConfigurationValue getConfigurationValue(final TenantConfigurationKey configurationKey, + final Class propertyType) { + validateTenantConfigurationDataType(configurationKey, propertyType); + + final TenantConfiguration tenantConfiguration = tenantConfigurationRepository + .findByKey(configurationKey.getKeyName()); + + return buildTenantConfigurationValueByKey(configurationKey, propertyType, tenantConfiguration); + } + + /** + * Validates the data type of the tenant configuration. If it is possible to + * cast to the given data type. + * + * @param configurationKey + * the key + * @param propertyType + * the class + */ + static void validateTenantConfigurationDataType(final TenantConfigurationKey configurationKey, + final Class propertyType) { + if (!configurationKey.getDataType().isAssignableFrom(propertyType)) { + throw new TenantConfigurationValidatorException( + String.format("Cannot parse the database value of type %s into the type %s.", + configurationKey.getDataType(), propertyType)); + } + } + + @Override + public TenantConfigurationValue buildTenantConfigurationValueByKey( + final TenantConfigurationKey configurationKey, final Class propertyType, + final TenantConfiguration tenantConfiguration) { + if (tenantConfiguration != null) { + return TenantConfigurationValue. builder().global(false).createdBy(tenantConfiguration.getCreatedBy()) + .createdAt(tenantConfiguration.getCreatedAt()) + .lastModifiedAt(tenantConfiguration.getLastModifiedAt()) + .lastModifiedBy(tenantConfiguration.getLastModifiedBy()) + .value(conversionService.convert(tenantConfiguration.getValue(), propertyType)).build(); + + } else if (configurationKey.getDefaultKeyName() != null) { + + return TenantConfigurationValue. builder().global(true).createdBy(null).createdAt(null) + .lastModifiedAt(null).lastModifiedBy(null) + .value(getGlobalConfigurationValue(configurationKey, propertyType)).build(); + } + return null; + } + + @Override + public TenantConfigurationValue getConfigurationValue(final TenantConfigurationKey configurationKey) { + return getConfigurationValue(configurationKey, configurationKey.getDataType()); + } + + @Override + public T getGlobalConfigurationValue(final TenantConfigurationKey configurationKey, + final Class propertyType) { + + if (!configurationKey.getDataType().isAssignableFrom(propertyType)) { + throw new TenantConfigurationValidatorException( + String.format("Cannot parse the database value of type %s into the type %s.", + configurationKey.getDataType(), propertyType)); + } + + final T valueInProperties = environment.getProperty(configurationKey.getDefaultKeyName(), propertyType); + + if (valueInProperties == null) { + return conversionService.convert(configurationKey.getDefaultValue(), propertyType); + } + + return valueInProperties; + } + + @Override + @CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()") + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public TenantConfigurationValue addOrUpdateConfiguration(final TenantConfigurationKey configurationKey, + final T value) { + + if (!configurationKey.getDataType().isAssignableFrom(value.getClass())) { + throw new TenantConfigurationValidatorException(String.format( + "Cannot parse the value %s of type %s into the type %s defined by the configuration key.", value, + value.getClass(), configurationKey.getDataType())); + } + + configurationKey.validate(applicationContext, value); + + JpaTenantConfiguration tenantConfiguration = tenantConfigurationRepository + .findByKey(configurationKey.getKeyName()); + + if (tenantConfiguration == null) { + tenantConfiguration = new JpaTenantConfiguration(configurationKey.getKeyName(), value.toString()); + } else { + tenantConfiguration.setValue(value.toString()); + } + + final JpaTenantConfiguration updatedTenantConfiguration = tenantConfigurationRepository + .save(tenantConfiguration); + + @SuppressWarnings("unchecked") + final Class clazzT = (Class) value.getClass(); + + return TenantConfigurationValue. builder().global(false).createdBy(updatedTenantConfiguration.getCreatedBy()) + .createdAt(updatedTenantConfiguration.getCreatedAt()) + .lastModifiedAt(updatedTenantConfiguration.getLastModifiedAt()) + .lastModifiedBy(updatedTenantConfiguration.getLastModifiedBy()) + .value(conversionService.convert(updatedTenantConfiguration.getValue(), clazzT)).build(); + } + + @Override + @CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()") + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public void deleteConfiguration(final TenantConfigurationKey configurationKey) { + tenantConfigurationRepository.deleteByKey(configurationKey.getKeyName()); + } + + @Override + public void setEnvironment(final Environment environment) { + this.environment = environment; + } +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantStatsManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantStatsManagement.java similarity index 66% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantStatsManagement.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantStatsManagement.java index c124037fa..83f37304a 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantStatsManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantStatsManagement.java @@ -6,24 +6,25 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.Optional; -import org.eclipse.hawkbit.report.model.TenantUsage; +import org.eclipse.hawkbit.repository.TenantStatsManagement; +import org.eclipse.hawkbit.repository.report.model.TenantUsage; +import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.beans.factory.annotation.Autowired; -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; /** - * Management service for stats of a single tenant. + * Management service for statistics of a single tenant. * */ @Validated -@Service -public class TenantStatsManagement { +public class JpaTenantStatsManagement implements TenantStatsManagement { @Autowired private TargetRepository targetRepository; @@ -34,17 +35,14 @@ public class TenantStatsManagement { @Autowired private ActionRepository actionRepository; - /** - * Service for stats of a single tenant. Opens a new transaction and as a - * result can an be used for multiple tenants, i.e. to allow in one session - * to collect data of all tenants in the system. - * - * @param tenant - * to collect for - * @return collected statistics - */ - @Transactional(propagation = Propagation.REQUIRES_NEW) - public TenantUsage getStatsOfTenant(final String tenant) { + @Autowired + private TenantAware tenantAware; + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_UNCOMMITTED) + public TenantUsage getStatsOfTenant() { + final String tenant = tenantAware.getCurrentTenant(); + final TenantUsage result = new TenantUsage(tenant); result.setTargets(targetRepository.count()); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/LocalArtifactRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/LocalArtifactRepository.java similarity index 90% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/LocalArtifactRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/LocalArtifactRepository.java index 4c106957d..e6eb62a27 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/LocalArtifactRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/LocalArtifactRepository.java @@ -6,11 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.List; import java.util.Optional; +import org.eclipse.hawkbit.repository.jpa.model.JpaLocalArtifact; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -23,7 +24,7 @@ import org.springframework.transaction.annotation.Transactional; * */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -public interface LocalArtifactRepository extends BaseEntityRepository { +public interface LocalArtifactRepository extends BaseEntityRepository { /** * Counts artifacts size where the related software module is not @@ -31,7 +32,7 @@ public interface LocalArtifactRepository extends BaseEntityRepository getSumOfUndeletedArtifactSize(); /** @@ -60,7 +61,7 @@ public interface LocalArtifactRepository extends BaseEntityRepository, JpaSpecificationExecutor { + extends BaseEntityRepository, JpaSpecificationExecutor { /** * Retrieves all {@link RolloutGroup} referring a specific rollout in the @@ -36,7 +38,7 @@ public interface RolloutGroupRepository * the rollout the rolloutgroups belong to * @return the rollout groups belonging to a rollout ordered by ID ASC. */ - List findByRolloutOrderByIdAsc(final Rollout rollout); + List findByRolloutOrderByIdAsc(final JpaRollout rollout); /** * Retrieves all {@link RolloutGroup} referring a specific rollout in a @@ -48,7 +50,7 @@ public interface RolloutGroupRepository * the status of the rollout groups * @return the rollout groups belonging to a rollout in a specific status */ - List findByRolloutAndStatus(final Rollout rollout, final RolloutGroupStatus status); + List findByRolloutAndStatus(final Rollout rollout, final RolloutGroupStatus status); /** * Counts all {@link RolloutGroup} referring a specific rollout. @@ -57,7 +59,7 @@ public interface RolloutGroupRepository * the rollout the rolloutgroup belong to * @return the count of the rollout groups for a specific rollout */ - Long countByRollout(final Rollout rollout); + Long countByRollout(final JpaRollout rollout); /** * Counts all {@link RolloutGroup} referring a specific rollout in a @@ -70,7 +72,7 @@ public interface RolloutGroupRepository * @return the count of rollout groups belonging to a rollout in a specific * status */ - Long countByRolloutAndStatus(Rollout rollout, RolloutGroupStatus rolloutGroupStatus); + Long countByRolloutAndStatus(JpaRollout rollout, RolloutGroupStatus rolloutGroupStatus); /** * Counts all {@link RolloutGroup} referring a specific rollout in specific @@ -88,8 +90,8 @@ public interface RolloutGroupRepository * @return the count of rollout groups belonging to a rollout in specific * status */ - @Query("SELECT COUNT(r.id) FROM RolloutGroup r WHERE r.rollout = :rollout and (r.status = :status1 or r.status = :status2)") - Long countByRolloutAndStatusOrStatus(@Param("rollout") Rollout rollout, + @Query("SELECT COUNT(r.id) FROM JpaRolloutGroup r WHERE r.rollout = :rollout and (r.status = :status1 or r.status = :status2)") + Long countByRolloutAndStatusOrStatus(@Param("rollout") JpaRollout rollout, @Param("status1") RolloutGroupStatus rolloutGroupStatus1, @Param("status2") RolloutGroupStatus rolloutGroupStatus2); @@ -103,7 +105,7 @@ public interface RolloutGroupRepository * the status of the rolloutgroups * @return The child {@link RolloutGroup}s in a specific status */ - List findByParentAndStatus(RolloutGroup rolloutGroup, RolloutGroupStatus status); + List findByParentAndStatus(JpaRolloutGroup rolloutGroup, RolloutGroupStatus status); /** * Retrieves all {@link RolloutGroup} for a specific rollout and status not @@ -116,7 +118,7 @@ public interface RolloutGroupRepository * @return rolloutgroup referring to a rollout and not having a specific * status ordered by ID DESC. */ - List findByRolloutAndStatusNotOrderByIdDesc(Rollout rollout, RolloutGroupStatus notStatus); + List findByRolloutAndStatusNotOrderByIdDesc(JpaRollout rollout, RolloutGroupStatus notStatus); /** * Retrieves all {@link RolloutGroup} for a specific rollout. @@ -127,6 +129,6 @@ public interface RolloutGroupRepository * the page request to sort, limit the result * @return a page of found {@link RolloutGroup} or {@code empty}. */ - Page findByRolloutId(final Long rolloutId, Pageable page); + Page findByRolloutId(final Long rolloutId, Pageable page); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RolloutRepository.java similarity index 82% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RolloutRepository.java index 5a22f5ab5..74d47d99a 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RolloutRepository.java @@ -6,10 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.List; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.springframework.data.domain.Page; @@ -25,7 +26,8 @@ import org.springframework.transaction.annotation.Transactional; * The repository interface for the {@link Rollout} model. */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -public interface RolloutRepository extends BaseEntityRepository, JpaSpecificationExecutor { +public interface RolloutRepository + extends BaseEntityRepository, JpaSpecificationExecutor { /** * Updates the {@code lastCheck} field of the {@link Rollout} for rollouts @@ -42,7 +44,7 @@ public interface RolloutRepository extends BaseEntityRepository, */ @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Query("UPDATE Rollout r SET r.lastCheck = :lastCheck WHERE r.lastCheck < (:lastCheck - :delay) AND r.status=:status") + @Query("UPDATE JpaRollout 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); @@ -57,7 +59,7 @@ public interface RolloutRepository extends BaseEntityRepository, * @return the list of {@link Rollout} for specific lastCheck time and * status */ - List findByLastCheckAndStatus(long lastCheck, RolloutStatus status); + List findByLastCheckAndStatus(long lastCheck, RolloutStatus status); /** * Retrieves all {@link Rollout} for a specific {@code name} @@ -66,7 +68,7 @@ public interface RolloutRepository extends BaseEntityRepository, * the rollout name * @return {@link Rollout} for specific name */ - Page findByName(final Pageable pageable, String name); + Page findByName(final Pageable pageable, String name); /** * Retrieves all {@link Rollout} for a specific {@code name} @@ -75,7 +77,7 @@ public interface RolloutRepository extends BaseEntityRepository, * the rollout name * @return {@link Rollout} for specific name */ - Rollout findByName(String name); + JpaRollout findByName(String name); /** * Retrieves all {@link Rollout} for a specific status. @@ -84,5 +86,5 @@ public interface RolloutRepository extends BaseEntityRepository, * the status of the rollouts to retrieve * @return a list of {@link Rollout} having the given status */ - List findByStatus(final RolloutStatus status); + List findByStatus(final RolloutStatus status); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutTargetGroupRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RolloutTargetGroupRepository.java similarity index 83% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutTargetGroupRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RolloutTargetGroupRepository.java index 14d9b8353..8cb267c69 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutTargetGroupRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RolloutTargetGroupRepository.java @@ -6,10 +6,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; -import org.eclipse.hawkbit.repository.model.RolloutTargetGroup; -import org.eclipse.hawkbit.repository.model.RolloutTargetGroupId; +import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup; +import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroupId; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.transaction.annotation.Isolation; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleMetadataRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleMetadataRepository.java similarity index 79% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleMetadataRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleMetadataRepository.java index c40a96e92..c962b31ec 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleMetadataRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleMetadataRepository.java @@ -6,12 +6,13 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.List; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.model.SwMetadataCompositeKey; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; @@ -25,8 +26,8 @@ import org.springframework.transaction.annotation.Transactional; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface SoftwareModuleMetadataRepository - extends PagingAndSortingRepository, - JpaSpecificationExecutor { + extends PagingAndSortingRepository, + JpaSpecificationExecutor { /** * Saves all given entities. @@ -37,7 +38,7 @@ public interface SoftwareModuleMetadataRepository * in case the given entity is (@literal null}. */ @Override - List save(Iterable entities); + List save(Iterable entities); /** * finds all software module meta data of the given software module id. diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleRepository.java similarity index 76% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleRepository.java index 95b01c270..08c84b349 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleRepository.java @@ -6,10 +6,13 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.List; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; @@ -30,7 +33,7 @@ import org.springframework.transaction.annotation.Transactional; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface SoftwareModuleRepository - extends BaseEntityRepository, JpaSpecificationExecutor { + extends BaseEntityRepository, JpaSpecificationExecutor { /** * Counts all {@link SoftwareModule}s based on the given {@link Type}. @@ -39,7 +42,7 @@ public interface SoftwareModuleRepository * to count for * @return number of {@link SoftwareModule}s */ - Long countByType(SoftwareModuleType type); + Long countByType(JpaSoftwareModuleType type); /** * Retrieves {@link SoftwareModule} by filtering on name AND version AND @@ -54,7 +57,7 @@ public interface SoftwareModuleRepository * @return the found {@link SoftwareModule} with the given name AND version * AND type */ - SoftwareModule findOneByNameAndVersionAndType(String name, String version, SoftwareModuleType type); + JpaSoftwareModule findOneByNameAndVersionAndType(String name, String version, JpaSoftwareModuleType type); /** * deletes the {@link SoftwareModule}s with the given IDs. @@ -69,7 +72,7 @@ public interface SoftwareModuleRepository */ @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Query("UPDATE SoftwareModule b SET b.deleted = 1, b.lastModifiedAt = :lastModifiedAt, b.lastModifiedBy = :lastModifiedBy WHERE b.id IN :ids") + @Query("UPDATE JpaSoftwareModule 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); @@ -81,7 +84,7 @@ public interface SoftwareModuleRepository * @return all {@link SoftwareModule}s that are assigned to given * {@link DistributionSet}. */ - Page findByAssignedTo(Pageable pageable, DistributionSet set); + Page findByAssignedTo(Pageable pageable, JpaDistributionSet set); /** * @@ -92,7 +95,7 @@ public interface SoftwareModuleRepository * {@link DistributionSet} */ @EntityGraph(value = "SoftwareModule.artifacts", type = EntityGraphType.LOAD) - List findByAssignedTo(DistributionSet set); + List findByAssignedTo(JpaDistributionSet set); /** * @param pageable @@ -104,7 +107,7 @@ public interface SoftwareModuleRepository * @return all {@link SoftwareModule}s that are assigned to given * {@link DistributionSet} filtered by {@link SoftwareModuleType}. */ - Page findByAssignedToAndType(Pageable pageable, DistributionSet set, SoftwareModuleType type); + Page findByAssignedToAndType(Pageable pageable, JpaDistributionSet set, JpaSoftwareModuleType type); /** * retrieves all software modules with a given {@link SoftwareModuleType} @@ -117,11 +120,11 @@ public interface SoftwareModuleRepository * @return {@link List} of found {@link SoftwareModule}s */ // Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477 - @Query("SELECT sm FROM SoftwareModule sm WHERE sm.id IN ?1 and sm.type = ?2") - List findByIdInAndType(Iterable ids, SoftwareModuleType type); + @Query("SELECT sm FROM JpaSoftwareModule sm WHERE sm.id IN ?1 and sm.type = ?2") + List findByIdInAndType(Iterable ids, JpaSoftwareModuleType type); @Override - List save(Iterable entities); + List save(Iterable entities); /** * retrieves all software modules with a given @@ -132,6 +135,6 @@ public interface SoftwareModuleRepository * @return {@link List} of found {@link SoftwareModule}s */ // Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477 - @Query("SELECT sm FROM SoftwareModule sm WHERE sm.id IN ?1") - List findByIdIn(Iterable ids); + @Query("SELECT sm FROM JpaSoftwareModule sm WHERE sm.id IN ?1") + List findByIdIn(Iterable ids); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleTypeRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleTypeRepository.java similarity index 84% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleTypeRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleTypeRepository.java index ac9425a08..c4ecfbd74 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleTypeRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleTypeRepository.java @@ -6,8 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -21,7 +22,7 @@ import org.springframework.transaction.annotation.Transactional; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface SoftwareModuleTypeRepository - extends BaseEntityRepository, JpaSpecificationExecutor { + extends BaseEntityRepository, JpaSpecificationExecutor { /** * @param pageable @@ -47,7 +48,7 @@ public interface SoftwareModuleTypeRepository * @return all {@link SoftwareModuleType}s in the repository with given * {@link SoftwareModuleType#getKey()} */ - SoftwareModuleType findByKey(String key); + JpaSoftwareModuleType findByKey(String key); /** * @@ -56,5 +57,5 @@ public interface SoftwareModuleTypeRepository * @return all {@link SoftwareModuleType}s in the repository with given * {@link SoftwareModuleType#getName()} */ - SoftwareModuleType findByName(String name); + JpaSoftwareModuleType findByName(String name); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SystemManagementCacheKeyGenerator.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SystemManagementCacheKeyGenerator.java new file mode 100644 index 000000000..2bed4aeff --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SystemManagementCacheKeyGenerator.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import java.lang.reflect.Method; + +import org.eclipse.hawkbit.tenancy.TenantAware; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.cache.interceptor.SimpleKeyGenerator; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Service; + +/** + * Implementation of {@link CurrentTenantCacheKeyGenerator}. + * + */ +@Service +public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyGenerator { + + @Autowired + private TenantAware tenantAware; + + private final ThreadLocal createInitialTenant = new ThreadLocal<>(); + + /** + * A implementation of the {@link KeyGenerator} to generate a key based on + * either the {@code createInitialTenant} thread local and the + * {@link TenantAware}, but in case we are in a tenant creation with its + * default types we need to use the tenant the current tenant which is + * currently created and not the one currently in the {@link TenantAware}. + * + */ + public 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) { + return SimpleKeyGenerator.generateKey(tenantAware.getCurrentTenant().toUpperCase(), + tenantAware.getCurrentTenant().toUpperCase()); + } + return SimpleKeyGenerator.generateKey(initialTenantCreation.toUpperCase(), + initialTenantCreation.toUpperCase()); + } + } + + @Override + @Bean + public KeyGenerator currentTenantKeyGenerator() { + return new CurrentTenantKeyGenerator(); + } + + ThreadLocal getCreateInitialTenant() { + return createInitialTenant; + } + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetFilterQueryRepository.java similarity index 78% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetFilterQueryRepository.java index 3604785cd..1f2fec8d8 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetFilterQueryRepository.java @@ -6,8 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.springframework.data.domain.Page; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; @@ -21,7 +22,7 @@ import org.springframework.transaction.annotation.Transactional; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface TargetFilterQueryRepository - extends BaseEntityRepository, JpaSpecificationExecutor { + extends BaseEntityRepository, JpaSpecificationExecutor { /** * Find customer target filter by name @@ -35,11 +36,11 @@ public interface TargetFilterQueryRepository * Find list of all custom target filters. */ @Override - Page findAll(); + Page findAll(); @Override @Modifying @Transactional - S save(S entity); + S save(S entity); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetInfoRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetInfoRepository.java similarity index 88% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetInfoRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetInfoRepository.java index 436f1e7b6..815fa3961 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetInfoRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetInfoRepository.java @@ -6,13 +6,14 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.Collection; import java.util.List; import javax.persistence.Entity; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.springframework.cache.annotation.CacheEvict; @@ -42,7 +43,7 @@ public interface TargetInfoRepository { */ @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Query("update TargetInfo ti set ti.updateStatus = :status where ti.targetId in :targets and ti.updateStatus != :status") + @Query("update JpaTargetInfo ti set ti.updateStatus = :status where ti.targetId in :targets and ti.updateStatus != :status") void setTargetUpdateStatus(@Param("status") TargetUpdateStatus status, @Param("targets") List targets); /** @@ -54,7 +55,7 @@ public interface TargetInfoRepository { * @return persisted or updated {@link Entity} */ @CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true) - S save(S entity); + S save(S entity); /** * Deletes info entries by ID. diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetRepository.java similarity index 83% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetRepository.java index 5e37902ab..0d84a3cad 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetRepository.java @@ -6,16 +6,18 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.Collection; import java.util.List; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.Tag; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetWithActionStatus; import org.springframework.cache.annotation.CacheEvict; @@ -35,7 +37,7 @@ import org.springframework.transaction.annotation.Transactional; * */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -public interface TargetRepository extends BaseEntityRepository, JpaSpecificationExecutor { +public interface TargetRepository extends BaseEntityRepository, JpaSpecificationExecutor { /** * Loads {@link Target} including details {@link EntityGraph} by given ID. @@ -45,7 +47,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp * @return found {@link Target} or null if not found. */ @EntityGraph(value = "Target.detail", type = EntityGraphType.LOAD) - Target findByControllerId(String controllerID); + JpaTarget findByControllerId(String controllerID); /** * Finds targets by given list of {@link Target#getControllerId()}s. @@ -65,7 +67,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp @Modifying @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") + @Query("DELETE FROM JpaTarget t WHERE t.id IN ?1") void deleteByIdIn(final Collection targetIDs); /** @@ -75,8 +77,8 @@ public interface TargetRepository extends BaseEntityRepository, Jp * to be found * @return list of found targets */ - @Query(value = "SELECT DISTINCT t FROM Target t JOIN t.tags tt WHERE tt = :tag") - List findByTag(@Param("tag") final TargetTag tag); + @Query(value = "SELECT DISTINCT t FROM JpaTarget t JOIN t.tags tt WHERE tt = :tag") + List findByTag(@Param("tag") final JpaTargetTag tag); /** * Finds all {@link Target}s based on given {@link Target#getControllerId()} @@ -88,7 +90,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp * to search for * @return {@link List} of found {@link Target}s. */ - @Query(value = "SELECT DISTINCT t from Target t JOIN t.tags tt WHERE tt.name = :tagname AND t.controllerId IN :targets") + @Query(value = "SELECT DISTINCT t from JpaTarget t JOIN t.tags tt WHERE tt.name = :tagname AND t.controllerId IN :targets") List findByTagNameAndControllerIdIn(@Param("tagname") final String tag, @Param("targets") final Collection controllerIds); @@ -114,7 +116,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp * * @return found targets */ - Page findByTargetInfoInstalledDistributionSet(final Pageable pageable, final DistributionSet set); + Page findByTargetInfoInstalledDistributionSet(final Pageable pageable, final JpaDistributionSet set); /** * retrieves the {@link Target}s which has the {@link DistributionSet} @@ -138,7 +140,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp * * @return found targets */ - Page findByAssignedDistributionSet(final Pageable pageable, final DistributionSet set); + Page findByAssignedDistributionSet(final Pageable pageable, final JpaDistributionSet set); /** * Saves all given {@link Target}s. @@ -154,7 +156,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) @CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true) - List save(Iterable entities); + List save(Iterable entities); /** * Saves a given entity. Use the returned instance for further operations as @@ -168,7 +170,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) @CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true) - S save(S entity); + S save(S entity); /** * Finds all targets that have defined {@link DistributionSet} assigned. @@ -199,7 +201,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp * @return number of found {@link Target}s with given * {@link Target#getControllerId()}s */ - @Query("SELECT COUNT(t) FROM Target t WHERE t.controllerId IN ?1") + @Query("SELECT COUNT(t) FROM JpaTarget t WHERE t.controllerId IN ?1") Long countByControllerIdIn(final Collection ids); /** @@ -228,7 +230,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp * @return found targets */ Page findByAssignedDistributionSetOrTargetInfoInstalledDistributionSet(final Pageable pageable, - final DistributionSet assigned, final DistributionSet installed); + final JpaDistributionSet assigned, final JpaDistributionSet installed); /** * Finds all targets that have defined {@link DistributionSet} assigned or @@ -255,12 +257,12 @@ public interface TargetRepository extends BaseEntityRepository, Jp * @see org.springframework.data.repository.CrudRepository#findAll() */ @Override - List findAll(); + List findAll(); @Override // Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477 - @Query("SELECT t FROM Target t WHERE t.id IN ?1") - List findAll(Iterable ids); + @Query("SELECT t FROM JpaTarget t WHERE t.id IN ?1") + List findAll(Iterable ids); /** * Sets {@link Target#getAssignedDistributionSet()}. @@ -276,11 +278,11 @@ public interface TargetRepository extends BaseEntityRepository, Jp */ @Modifying @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, + @Query("UPDATE JpaTarget t SET t.assignedDistributionSet = :set, t.lastModifiedAt = :lastModifiedAt, t.lastModifiedBy = :lastModifiedBy WHERE t.id IN :targets") + void setAssignedDistributionSet(@Param("set") JpaDistributionSet set, @Param("lastModifiedAt") Long modifiedAt, @Param("lastModifiedBy") String modifiedBy, @Param("targets") Collection targets); - List findByRolloutTargetGroupRolloutGroup(final RolloutGroup rolloutGroup); + List findByRolloutTargetGroupRolloutGroup(final JpaRolloutGroup rolloutGroup); /** * @@ -304,7 +306,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp * the page request parameter * @return a page of all targets related to a rollout group */ - Page findByActionsRolloutGroup(RolloutGroup rolloutGroup, Pageable page); + Page findByActionsRolloutGroup(JpaRolloutGroup rolloutGroup, Pageable page); /** * Find all targets with action status for a specific group. @@ -315,7 +317,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp * the ID of the rollout group * @return targets with action status */ - @Query("select DISTINCT NEW org.eclipse.hawkbit.repository.model.TargetWithActionStatus(a.target,a.status) from Action a inner join fetch a.target t where a.rolloutGroup.id = :rolloutGroupId") + @Query("select DISTINCT NEW org.eclipse.hawkbit.repository.model.TargetWithActionStatus(a.target,a.status) from JpaAction a inner join fetch a.target t where a.rolloutGroup.id = :rolloutGroupId") Page findTargetsWithActionStatusByRolloutGroupId(final Pageable pageable, @Param("rolloutGroupId") Long rolloutGroupId); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetTagRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTagRepository.java similarity index 79% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetTagRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTagRepository.java index e0f03ee78..6b9e021b1 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetTagRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTagRepository.java @@ -6,10 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.List; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.model.TargetTag; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; @@ -22,7 +23,7 @@ import org.springframework.transaction.annotation.Transactional; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface TargetTagRepository - extends BaseEntityRepository, JpaSpecificationExecutor { + extends BaseEntityRepository, JpaSpecificationExecutor { /** * deletes the {@link TargetTag}s with the given tag names. @@ -42,7 +43,7 @@ public interface TargetTagRepository * to filter on * @return the {@link TargetTag} if found, otherwise null */ - TargetTag findByNameEquals(final String tagName); + JpaTargetTag findByNameEquals(final String tagName); /** * Returns all instances of the type. @@ -50,8 +51,8 @@ public interface TargetTagRepository * @return all entities */ @Override - List findAll(); + List findAll(); @Override - List save(Iterable entities); + List save(Iterable entities); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantConfigurationRepository.java similarity index 83% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantConfigurationRepository.java index 0497ea924..bd99cb918 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantConfigurationRepository.java @@ -6,10 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.List; +import org.eclipse.hawkbit.repository.jpa.model.JpaTenantConfiguration; import org.eclipse.hawkbit.repository.model.TenantConfiguration; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; @@ -19,7 +20,7 @@ import org.springframework.transaction.annotation.Transactional; * */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -public interface TenantConfigurationRepository extends BaseEntityRepository { +public interface TenantConfigurationRepository extends BaseEntityRepository { /** * Finds a specific {@link TenantConfiguration} by the configuration key. @@ -28,10 +29,10 @@ public interface TenantConfigurationRepository extends BaseEntityRepository findAll(); + List findAll(); /** * Deletes a tenant configuration by tenant and key. diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantKeyGenerator.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantKeyGenerator.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantKeyGenerator.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantKeyGenerator.java index 3265b622c..0478d99d7 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantKeyGenerator.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantKeyGenerator.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.lang.reflect.Method; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantMetaDataRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantMetaDataRepository.java similarity index 89% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantMetaDataRepository.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantMetaDataRepository.java index 4aa4c48dc..353f6500b 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantMetaDataRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantMetaDataRepository.java @@ -6,10 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import java.util.List; +import org.eclipse.hawkbit.repository.jpa.model.JpaTenantMetaData; import org.eclipse.hawkbit.repository.model.TenantMetaData; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.transaction.annotation.Isolation; @@ -20,7 +21,7 @@ import org.springframework.transaction.annotation.Transactional; * */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -public interface TenantMetaDataRepository extends PagingAndSortingRepository { +public interface TenantMetaDataRepository extends PagingAndSortingRepository { /** * Search {@link TenantMetaData} by tenant name. @@ -42,7 +43,7 @@ public interface TenantMetaDataRepository extends PagingAndSortingRepository findAll(); + List findAll(); /** * @param tenant diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/aspects/ExceptionMappingAspectHandler.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/aspects/ExceptionMappingAspectHandler.java similarity index 99% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/aspects/ExceptionMappingAspectHandler.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/aspects/ExceptionMappingAspectHandler.java index c3da509aa..be21cdfe7 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/aspects/ExceptionMappingAspectHandler.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/aspects/ExceptionMappingAspectHandler.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.aspects; +package org.eclipse.hawkbit.repository.jpa.aspects; import java.sql.SQLException; import java.util.ArrayList; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheField.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/cache/CacheField.java similarity index 89% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheField.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/cache/CacheField.java index 8909c1125..b4e322c77 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheField.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/cache/CacheField.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.cache; +package org.eclipse.hawkbit.repository.jpa.cache; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -14,7 +14,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import org.eclipse.hawkbit.eventbus.CacheFieldEntityListener; +import org.eclipse.hawkbit.repository.jpa.model.CacheFieldEntityListener; import org.springframework.cache.CacheManager; import org.springframework.data.annotation.Transient; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheKeys.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/cache/CacheKeys.java similarity index 89% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheKeys.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/cache/CacheKeys.java index 9cb53a317..021a17a9d 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheKeys.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/cache/CacheKeys.java @@ -6,12 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.cache; +package org.eclipse.hawkbit.repository.jpa.cache; -import org.eclipse.hawkbit.eventbus.CacheFieldEntityListener; +import org.eclipse.hawkbit.repository.jpa.model.CacheFieldEntityListener; /** - * Constants for cache keys used in multiple classes. + * RepositoryConstants for cache keys used in multiple classes. * * * diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheWriteNotify.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/cache/CacheWriteNotify.java similarity index 80% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheWriteNotify.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/cache/CacheWriteNotify.java index bf690e07e..6dfdf157f 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheWriteNotify.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/cache/CacheWriteNotify.java @@ -6,11 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.cache; +package org.eclipse.hawkbit.repository.jpa.cache; -import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent; -import org.eclipse.hawkbit.eventbus.event.RolloutGroupCreatedEvent; -import org.eclipse.hawkbit.repository.model.Action; +import java.math.RoundingMode; + +import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupCreatedEvent; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.tenancy.TenantAware; @@ -20,6 +21,7 @@ import org.springframework.cache.CacheManager; import org.springframework.stereotype.Service; import com.google.common.eventbus.EventBus; +import com.google.common.math.DoubleMath; /** * An service which combines the functionality for functional use cases to write @@ -30,10 +32,6 @@ import com.google.common.eventbus.EventBus; */ @Service public class CacheWriteNotify { - - /** - * - */ private static final int DOWNLOAD_PROGRESS_MAX = 100; @Autowired @@ -46,20 +44,29 @@ public class CacheWriteNotify { private TenantAware tenantAware; /** - * writes the download progress in percentage into the cache + * writes the download progress into the cache * {@link CacheKeys#DOWNLOAD_PROGRESS_PERCENT} and notifies the * {@link EventBus} with a {@link DownloadProgressEvent}. * * @param statusId * the ID of the {@link ActionStatus} - * @param progressPercent - * the progress in percentage which must be between 0-100 + * @param requestedBytes + * requested bytes of the request + * @param shippedBytesSinceLast + * since last event + * @param shippedBytesOverall + * for the download request */ - public void downloadProgressPercent(final long statusId, final int progressPercent) { + public void downloadProgress(final Long statusId, final Long requestedBytes, final Long shippedBytesSinceLast, + final Long shippedBytesOverall) { - final Cache cache = cacheManager.getCache(Action.class.getName()); + final Cache cache = cacheManager.getCache(ActionStatus.class.getName()); final String cacheKey = CacheKeys.entitySpecificCacheKey(String.valueOf(statusId), CacheKeys.DOWNLOAD_PROGRESS_PERCENT); + + final int progressPercent = DoubleMath.roundToInt(shippedBytesOverall * 100.0 / requestedBytes, + RoundingMode.DOWN); + if (progressPercent < DOWNLOAD_PROGRESS_MAX) { cache.put(cacheKey, progressPercent); } else { @@ -69,7 +76,8 @@ public class CacheWriteNotify { cache.evict(cacheKey); } - eventBus.post(new DownloadProgressEvent(tenantAware.getCurrentTenant(), statusId, progressPercent)); + eventBus.post(new DownloadProgressEvent(tenantAware.getCurrentTenant(), statusId, requestedBytes, + shippedBytesSinceLast, shippedBytesOverall)); } /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/Constants.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/configuration/Constants.java similarity index 94% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/Constants.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/configuration/Constants.java index ef0b70438..fb6a319f9 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/Constants.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/configuration/Constants.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.jpa.configuration; /** * A constant class which holds only static constants used within the SP server. diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/MultiTenantJpaTransactionManager.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/configuration/MultiTenantJpaTransactionManager.java similarity index 96% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/MultiTenantJpaTransactionManager.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/configuration/MultiTenantJpaTransactionManager.java index b3821e5f3..e8547c52b 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/MultiTenantJpaTransactionManager.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/configuration/MultiTenantJpaTransactionManager.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.jpa.configuration; import javax.persistence.EntityManager; import javax.transaction.Transaction; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/EntityChangeEventListener.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EntityChangeEventListener.java similarity index 86% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/EntityChangeEventListener.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EntityChangeEventListener.java index 7bfbd957e..5f41063d2 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/EntityChangeEventListener.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EntityChangeEventListener.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus; +package org.eclipse.hawkbit.repository.jpa.eventbus; import java.util.Collection; @@ -15,11 +15,12 @@ import javax.persistence.EntityManager; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; -import org.eclipse.hawkbit.eventbus.event.TargetCreatedEvent; 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.eventbus.event.TargetCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; +import org.eclipse.hawkbit.repository.jpa.TargetRepository; +import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; @@ -66,7 +67,7 @@ public class EntityChangeEventListener { * in case exception happens in the * {@link ProceedingJoinPoint#proceed()} */ - @Around("execution(* org.eclipse.hawkbit.repository.TargetInfoRepository.save(..))") + @Around("execution(* org.eclipse.hawkbit.repository.jpa.TargetInfoRepository.save(..))") // Exception squid:S00112 - Is aspectJ proxy @SuppressWarnings({ "squid:S00112" }) public Object targetCreated(final ProceedingJoinPoint joinpoint) throws Throwable { @@ -93,7 +94,7 @@ public class EntityChangeEventListener { * in case exception happens in the * {@link ProceedingJoinPoint#proceed()} */ - @Around("execution(* org.eclipse.hawkbit.repository.TargetRepository.deleteByIdIn(..))") + @Around("execution(* org.eclipse.hawkbit.repository.jpa.TargetRepository.deleteByIdIn(..))") // Exception squid:S00112 - Is aspectJ proxy @SuppressWarnings({ "squid:S00112" }) public Object targetDeletedById(final ProceedingJoinPoint joinpoint) throws Throwable { @@ -115,8 +116,8 @@ public class EntityChangeEventListener { * in case exception happens in the * {@link ProceedingJoinPoint#proceed()} */ - @Around("execution(* org.eclipse.hawkbit.repository.TargetRepository.delete(..))") - // Exception squid:S00112 - Is aspectJ proxy + @Around("execution(* org.eclipse.hawkbit.repository.jpa.TargetRepository.delete(..))") + // Exception squid:S00112 - Is aspectJ proxy @SuppressWarnings({ "squid:S00112", "unchecked" }) public Object targetDeleted(final ProceedingJoinPoint joinpoint) throws Throwable { final String currentTenant = tenantAware.getCurrentTenant(); @@ -146,8 +147,8 @@ public class EntityChangeEventListener { afterCommit.afterCommit(() -> eventBus.post(new TargetDeletedEvent(tenant, targetId))); } - private boolean isTargetInfoNew(final Object targetInfo) { - return ((TargetInfo) targetInfo).isNew(); + private static boolean isTargetInfoNew(final Object targetInfo) { + return ((JpaTargetInfo) targetInfo).isNew(); } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/EventMerger.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EventMerger.java similarity index 90% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/EventMerger.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EventMerger.java index fe4cf4b34..6a4302c5b 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/EventMerger.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EventMerger.java @@ -6,13 +6,21 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus.event; +package org.eclipse.hawkbit.repository.jpa.eventbus; import java.util.Iterator; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.eclipse.hawkbit.eventbus.EventSubscriber; +import org.eclipse.hawkbit.eventbus.event.Event; +import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutPropertyChangeEvent; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.springframework.beans.factory.annotation.Autowired; @@ -28,10 +36,8 @@ import com.google.common.eventbus.Subscribe; * interested in all fine grained events, e.g. UI code. The UI code is not * interested in handling the flood of events, so collecting the events and * merge them to one event together and post them in a fixed interval is easier - * to consume e.g. for push notifcations on UI. + * to consume e.g. for push notifications on UI. * - * @author Michael Hirsch - * */ @EventSubscriber public class EventMerger { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/executor/AfterTransactionCommitDefaultServiceExecutor.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/executor/AfterTransactionCommitDefaultServiceExecutor.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/executor/AfterTransactionCommitDefaultServiceExecutor.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/executor/AfterTransactionCommitDefaultServiceExecutor.java index 0d65b291e..6c58a0207 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/executor/AfterTransactionCommitDefaultServiceExecutor.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/executor/AfterTransactionCommitDefaultServiceExecutor.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.executor; +package org.eclipse.hawkbit.repository.jpa.executor; import java.util.ArrayList; import java.util.List; @@ -45,6 +45,8 @@ public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSyn } @Override + // Exception squid:S1217 - we want to run this synchronous + @SuppressWarnings("squid:S1217") public void afterCommit(final Runnable runnable) { LOGGER.debug("Submitting new runnable {} to run after transaction commit", runnable); if (TransactionSynchronizationManager.isSynchronizationActive()) { @@ -58,6 +60,7 @@ public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSyn return; } LOGGER.info("Transaction synchronization is NOT ACTIVE/ INACTIVE. Executing right now runnable {}", runnable); + runnable.run(); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/executor/AfterTransactionCommitExecutor.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/executor/AfterTransactionCommitExecutor.java similarity index 93% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/executor/AfterTransactionCommitExecutor.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/executor/AfterTransactionCommitExecutor.java index ab5c67bab..34b0e8d5f 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/executor/AfterTransactionCommitExecutor.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/executor/AfterTransactionCommitExecutor.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.executor; +package org.eclipse.hawkbit.repository.jpa.executor; /** * diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Artifact.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaArtifact.java similarity index 74% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Artifact.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaArtifact.java index b384a3100..6ead1df9e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Artifact.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaArtifact.java @@ -6,17 +6,23 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Column; import javax.persistence.MappedSuperclass; +import org.eclipse.hawkbit.repository.model.Artifact; +import org.eclipse.hawkbit.repository.model.SoftwareModule; + /** * Tenant specific locally stored artifact representation that is used by * {@link SoftwareModule}. */ @MappedSuperclass -public abstract class Artifact extends TenantAwareBaseEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public abstract class AbstractJpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Artifact { private static final long serialVersionUID = 1L; @Column(name = "sha1_hash", length = 40, nullable = true) @@ -28,12 +34,15 @@ public abstract class Artifact extends TenantAwareBaseEntity { @Column(name = "file_size") private Long size; + @Override public abstract SoftwareModule getSoftwareModule(); + @Override public String getMd5Hash() { return md5Hash; } + @Override public String getSha1Hash() { return sha1Hash; } @@ -46,6 +55,7 @@ public abstract class Artifact extends TenantAwareBaseEntity { this.sha1Hash = sha1Hash; } + @Override public Long getSize() { return size; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/BaseEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java similarity index 87% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/BaseEntity.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java index 65300c6c4..257828c6f 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/BaseEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java @@ -6,9 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; - -import java.io.Serializable; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Access; import javax.persistence.AccessType; @@ -20,14 +18,12 @@ import javax.persistence.Id; import javax.persistence.MappedSuperclass; import javax.persistence.Version; -import org.eclipse.hawkbit.eventbus.CacheFieldEntityListener; -import org.eclipse.hawkbit.eventbus.EntityPropertyChangeListener; +import org.eclipse.hawkbit.repository.model.BaseEntity; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import org.springframework.hateoas.Identifiable; /** * Holder of the base attributes common to all entities. @@ -36,7 +32,7 @@ import org.springframework.hateoas.Identifiable; @MappedSuperclass @Access(AccessType.FIELD) @EntityListeners({ AuditingEntityListener.class, CacheFieldEntityListener.class, EntityPropertyChangeListener.class }) -public abstract class BaseEntity implements Serializable, Identifiable { +public abstract class AbstractJpaBaseEntity implements BaseEntity { private static final long serialVersionUID = 1L; @Id @@ -56,28 +52,32 @@ public abstract class BaseEntity implements Serializable, Identifiable { /** * Default constructor needed for JPA entities. */ - public BaseEntity() { + public AbstractJpaBaseEntity() { // Default constructor needed for JPA entities. } + @Override @Access(AccessType.PROPERTY) @Column(name = "created_at", insertable = true, updatable = false) public Long getCreatedAt() { return createdAt; } + @Override @Access(AccessType.PROPERTY) @Column(name = "created_by", insertable = true, updatable = false, length = 40) public String getCreatedBy() { return createdBy; } + @Override @Access(AccessType.PROPERTY) @Column(name = "last_modified_at", insertable = false, updatable = true) public Long getLastModifiedAt() { return lastModifiedAt; } + @Override @Access(AccessType.PROPERTY) @Column(name = "last_modified_by", insertable = false, updatable = true, length = 40) public String getLastModifiedBy() { @@ -104,12 +104,12 @@ public abstract class BaseEntity implements Serializable, Identifiable { this.lastModifiedAt = lastModifiedAt; } + @Override public long getOptLockRevision() { return optLockRevision; } - // for test purposes only - void setOptLockRevision(final long optLockRevision) { + public void setOptLockRevision(final long optLockRevision) { this.optLockRevision = optLockRevision; } @@ -135,7 +135,9 @@ public abstract class BaseEntity implements Serializable, Identifiable { * @see java.lang.Object#hashCode() */ @Override - public int hashCode() { // NOSONAR - as this is generated code + // Exception squid:S864 - generated code + @SuppressWarnings({ "squid:S864" }) + public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (id == null ? 0 : id.hashCode()); @@ -152,8 +154,7 @@ public abstract class BaseEntity implements Serializable, Identifiable { * @see java.lang.Object#equals(java.lang.Object) */ @Override - public boolean equals(final Object obj) { // NOSONAR - as this is generated - // code + public boolean equals(final Object obj) { if (this == obj) { return true; } @@ -163,7 +164,7 @@ public abstract class BaseEntity implements Serializable, Identifiable { if (!(this.getClass().isInstance(obj))) { return false; } - final BaseEntity other = (BaseEntity) obj; + final AbstractJpaBaseEntity other = (AbstractJpaBaseEntity) obj; if (id == null) { if (other.id != null) { return false; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/MetaData.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaMetaData.java similarity index 84% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/MetaData.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaMetaData.java index c41a0e8c9..5a3f23ac3 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/MetaData.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaMetaData.java @@ -6,21 +6,21 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; - -import java.io.Serializable; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Id; import javax.persistence.MappedSuperclass; +import org.eclipse.hawkbit.repository.model.MetaData; + /** * Meta data for entities. * */ @MappedSuperclass -public abstract class MetaData implements Serializable { +public abstract class AbstractJpaMetaData implements MetaData { private static final long serialVersionUID = 1L; @Id @@ -31,28 +31,32 @@ public abstract class MetaData implements Serializable { @Basic private String value; - public MetaData(final String key, final String value) { + public AbstractJpaMetaData(final String key, final String value) { super(); this.key = key; this.value = value; } - public MetaData() { + public AbstractJpaMetaData() { // Default constructor needed for JPA entities } + @Override public String getKey() { return key; } + @Override public void setKey(final String key) { this.key = key; } + @Override public String getValue() { return value; } + @Override public void setValue(final String value) { this.value = value; } @@ -77,7 +81,7 @@ public abstract class MetaData implements Serializable { if (!(this.getClass().isInstance(obj))) { return false; } - final MetaData other = (MetaData) obj; + final AbstractJpaMetaData other = (AbstractJpaMetaData) obj; if (key == null) { if (other.key != null) { return false; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/NamedEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaNamedEntity.java similarity index 70% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/NamedEntity.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaNamedEntity.java index e14d88161..ebf5eac3c 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/NamedEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaNamedEntity.java @@ -6,17 +6,23 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Column; import javax.persistence.MappedSuperclass; +import org.eclipse.hawkbit.repository.model.NamedEntity; +import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; + /** * {@link TenantAwareBaseEntity} extension for all entities that are named in * addition to their technical ID. */ @MappedSuperclass -public abstract class NamedEntity extends TenantAwareBaseEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public abstract class AbstractJpaNamedEntity extends AbstractJpaTenantAwareBaseEntity implements NamedEntity { private static final long serialVersionUID = 1L; @Column(name = "name", nullable = false, length = 64) @@ -28,7 +34,7 @@ public abstract class NamedEntity extends TenantAwareBaseEntity { /** * Default constructor. */ - public NamedEntity() { + public AbstractJpaNamedEntity() { super(); } @@ -40,23 +46,27 @@ public abstract class NamedEntity extends TenantAwareBaseEntity { * @param description * of the {@link NamedEntity} */ - public NamedEntity(final String name, final String description) { + public AbstractJpaNamedEntity(final String name, final String description) { this.name = name; this.description = description; } + @Override public String getDescription() { return description; } + @Override public String getName() { return name; } + @Override public void setDescription(final String description) { this.description = description; } + @Override public void setName(final String name) { this.name = name; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/NamedVersionedEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaNamedVersionedEntity.java similarity index 64% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/NamedVersionedEntity.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaNamedVersionedEntity.java index fa56da197..ffdb1dfa6 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/NamedVersionedEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaNamedVersionedEntity.java @@ -6,17 +6,23 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Column; import javax.persistence.MappedSuperclass; +import org.eclipse.hawkbit.repository.model.NamedEntity; +import org.eclipse.hawkbit.repository.model.NamedVersionedEntity; + /** * Extension for {@link NamedEntity} that are versioned. * */ @MappedSuperclass -public abstract class NamedVersionedEntity extends NamedEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public abstract class AbstractJpaNamedVersionedEntity extends AbstractJpaNamedEntity implements NamedVersionedEntity { private static final long serialVersionUID = 1L; @Column(name = "version", nullable = false, length = 64) @@ -31,19 +37,21 @@ public abstract class NamedVersionedEntity extends NamedEntity { * of the entity * @param description */ - public NamedVersionedEntity(final String name, final String version, final String description) { + public AbstractJpaNamedVersionedEntity(final String name, final String version, final String description) { super(name, description); this.version = version; } - NamedVersionedEntity() { + AbstractJpaNamedVersionedEntity() { super(); } + @Override public String getVersion() { return version; } + @Override public void setVersion(final String version) { this.version = version; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Tag.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTag.java similarity index 73% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Tag.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTag.java index 23489ea12..b2e8163da 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Tag.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTag.java @@ -6,12 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Column; import javax.persistence.MappedSuperclass; -import org.springframework.hateoas.Identifiable; +import org.eclipse.hawkbit.repository.model.Tag; /** * A Tag can be used as describing and organizational meta information for any @@ -19,13 +19,16 @@ import org.springframework.hateoas.Identifiable; * */ @MappedSuperclass -public abstract class Tag extends NamedEntity implements Identifiable { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public abstract class AbstractJpaTag extends AbstractJpaNamedEntity implements Tag { private static final long serialVersionUID = 1L; @Column(name = "colour", nullable = true, length = 16) private String colour; - protected Tag() { + protected AbstractJpaTag() { super(); } @@ -39,15 +42,17 @@ public abstract class Tag extends NamedEntity implements Identifiable { * @param colour * of tag in UI */ - public Tag(final String name, final String description, final String colour) { + public AbstractJpaTag(final String name, final String description, final String colour) { super(name, description); this.colour = colour; } + @Override public String getColour() { return colour; } + @Override public void setColour(final String colour) { this.colour = colour; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantAwareBaseEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTenantAwareBaseEntity.java similarity index 84% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantAwareBaseEntity.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTenantAwareBaseEntity.java index d03a4938a..ccd4a30b1 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantAwareBaseEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTenantAwareBaseEntity.java @@ -6,15 +6,16 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Column; import javax.persistence.MappedSuperclass; import javax.persistence.PrePersist; import org.eclipse.hawkbit.repository.exception.TenantNotExistException; -import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder; -import org.eclipse.hawkbit.repository.model.helper.TenantAwareHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.SystemManagementHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder; +import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.eclipse.persistence.annotations.Multitenant; import org.eclipse.persistence.annotations.MultitenantType; import org.eclipse.persistence.annotations.TenantDiscriminatorColumn; @@ -26,7 +27,7 @@ import org.eclipse.persistence.annotations.TenantDiscriminatorColumn; @MappedSuperclass @TenantDiscriminatorColumn(name = "tenant", length = 40) @Multitenant(MultitenantType.SINGLE_TABLE) -public abstract class TenantAwareBaseEntity extends BaseEntity { +public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEntity implements TenantAwareBaseEntity { private static final long serialVersionUID = 1L; @Column(name = "tenant", nullable = false, insertable = false, updatable = false, length = 40) @@ -35,7 +36,7 @@ public abstract class TenantAwareBaseEntity extends BaseEntity { /** * Default constructor needed for JPA entities. */ - public TenantAwareBaseEntity() { + public AbstractJpaTenantAwareBaseEntity() { // Default constructor needed for JPA entities. } @@ -57,6 +58,7 @@ public abstract class TenantAwareBaseEntity extends BaseEntity { setTenant(currentTenant.toUpperCase()); } + @Override public String getTenant() { return tenant; } @@ -95,11 +97,13 @@ public abstract class TenantAwareBaseEntity extends BaseEntity { * @see org.eclipse.hawkbit.repository.model.BaseEntity#equals(java.lang.Object) */ @Override + // exception squid:S2259 - obj is checked for null in super + @SuppressWarnings("squid:S2259") public boolean equals(final Object obj) { if (!super.equals(obj)) { return false; } - final TenantAwareBaseEntity other = (TenantAwareBaseEntity) obj; + final AbstractJpaTenantAwareBaseEntity other = (AbstractJpaTenantAwareBaseEntity) obj; if (tenant == null) { if (other.tenant != null) { return false; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/CacheFieldEntityListener.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/CacheFieldEntityListener.java similarity index 60% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/CacheFieldEntityListener.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/CacheFieldEntityListener.java index 902462028..b303f33a4 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/CacheFieldEntityListener.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/CacheFieldEntityListener.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus; +package org.eclipse.hawkbit.repository.jpa.model; import java.io.Serializable; import java.lang.reflect.Field; @@ -15,9 +15,9 @@ import javax.persistence.PostLoad; import javax.persistence.PostRemove; import org.apache.commons.lang3.reflect.FieldUtils; -import org.eclipse.hawkbit.cache.CacheField; -import org.eclipse.hawkbit.cache.CacheKeys; -import org.eclipse.hawkbit.repository.model.helper.CacheManagerHolder; +import org.eclipse.hawkbit.repository.jpa.cache.CacheField; +import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys; +import org.eclipse.hawkbit.repository.jpa.model.helper.CacheManagerHolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.Cache; @@ -32,6 +32,9 @@ import org.springframework.hateoas.Identifiable; * by this entity listener cause the cache keys are calculated with the ID of * the entity. * + * + * + * */ public class CacheFieldEntityListener { @@ -45,21 +48,19 @@ public class CacheFieldEntityListener { */ @PostLoad public void postLoad(final Object target) { - if (!isIdentifiable(target)) { - return; - } - - final CacheFieldCallback cacheFieldCallback = (type, field, cacheKey, entityId) -> { + if (target instanceof Identifiable) { final CacheManager cacheManager = CacheManagerHolder.getInstance().getCacheManager(); - final Cache cache = cacheManager.getCache(type.getName()); - final ValueWrapper valueWrapper = cache - .get(CacheKeys.entitySpecificCacheKey(entityId.toString(), cacheKey)); - if (valueWrapper != null && valueWrapper.get() != null) { - FieldUtils.writeField(field, target, valueWrapper.get(), true); - } - }; - - findCacheFields((Identifiable) target, cacheFieldCallback); + @SuppressWarnings("rawtypes") + final String id = ((Identifiable) target).getId().toString(); + final Class type = target.getClass(); + findCacheFields(type, id, (field, cacheKey, id1) -> { + final Cache cache = cacheManager.getCache(type.getName()); + final ValueWrapper valueWrapper = cache.get(CacheKeys.entitySpecificCacheKey(id1.toString(), cacheKey)); + if (valueWrapper != null && valueWrapper.get() != null) { + FieldUtils.writeField(field, target, valueWrapper.get(), true); + } + }); + } } /** @@ -71,32 +72,26 @@ public class CacheFieldEntityListener { */ @PostRemove public void postDelete(final Object target) { - if (!isIdentifiable(target)) { - return; - } - final CacheFieldCallback cacheFieldCallback = (type, field, cacheKey, entityId) -> { + if (target instanceof Identifiable) { final CacheManager cacheManager = CacheManagerHolder.getInstance().getCacheManager(); - final Cache cache = cacheManager.getCache(type.getName()); - cache.evict(CacheKeys.entitySpecificCacheKey(entityId.toString(), cacheKey)); - }; - - findCacheFields((Identifiable) target, cacheFieldCallback); + @SuppressWarnings("rawtypes") + final String id = ((Identifiable) target).getId().toString(); + final Class type = target.getClass(); + findCacheFields(type, id, (field, cacheKey, id1) -> { + final Cache cache = cacheManager.getCache(type.getName()); + cache.evict(CacheKeys.entitySpecificCacheKey(id1.toString(), cacheKey)); + }); + } } - private boolean isIdentifiable(final Object target) { - return target instanceof Identifiable; - } - - private void findCacheFields(final Identifiable target, final CacheFieldCallback callback) { - final String id = target.getId().toString(); - final Class type = target.getClass(); - + private void findCacheFields(final Class type, final Serializable id, + final CacheFieldCallback callback) { final Field[] declaredFields = type.getDeclaredFields(); for (final Field field : declaredFields) { if (field.getAnnotation(CacheField.class) != null) { try { final CacheField annotation = field.getAnnotation(CacheField.class); - callback.fromCache(type, field, annotation.key(), id); + callback.fromCache(field, annotation.key(), id); } catch (final IllegalAccessException e) { LOGGER.error("cannot access the field {} for the entity {}, ignoring the cacheable field", field, type, e); @@ -108,23 +103,21 @@ public class CacheFieldEntityListener { @FunctionalInterface private interface CacheFieldCallback { /** - * callback methods which is called when a field is annotated with - * {@link CacheField}. + * callback methods which is called by the + * {@link CacheFieldEntityListener#findCacheFields(Class, Serializable, CacheFieldCallback)} + * in case a field is annotated with {@link CacheField}. * - * @param type - * the type of the target. * @param field * the field which is annotaed with {@link CacheField} * @param cacheKey * the configured cache key in the annotation * {@link CacheField#key()} - * @param entityId + * @param id * the ID of the entity * @throws IllegalAccessException * in case the field cannot be accessed */ - void fromCache(Class type, final Field field, final String cacheKey, Serializable entityId) - throws IllegalAccessException; + void fromCache(final Field field, final String cacheKey, Serializable id) throws IllegalAccessException; } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTypeElement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DistributionSetTypeElement.java similarity index 86% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTypeElement.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DistributionSetTypeElement.java index 8414a6f1a..26a603078 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTypeElement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DistributionSetTypeElement.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.io.Serializable; @@ -21,6 +21,10 @@ import javax.persistence.ManyToOne; import javax.persistence.MapsId; import javax.persistence.Table; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; + /** * Relation element between a {@link DistributionSetType} and its * {@link SoftwareModuleType} elements. @@ -40,12 +44,12 @@ public class DistributionSetTypeElement implements Serializable { @MapsId("dsType") @ManyToOne(optional = false, fetch = FetchType.LAZY) @JoinColumn(name = "distribution_set_type", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_type_element_dstype")) - private DistributionSetType dsType; + private JpaDistributionSetType dsType; @MapsId("smType") @ManyToOne(optional = false, fetch = FetchType.LAZY) @JoinColumn(name = "software_module_type", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_type_element_smtype")) - private SoftwareModuleType smType; + private JpaSoftwareModuleType smType; public DistributionSetTypeElement() { // Default constructor for JPA @@ -62,7 +66,7 @@ public class DistributionSetTypeElement implements Serializable { * to true if the {@link SoftwareModuleType} if * mandatory element in the {@link DistributionSet}. */ - public DistributionSetTypeElement(final DistributionSetType dsType, final SoftwareModuleType smType, + public DistributionSetTypeElement(final JpaDistributionSetType dsType, final JpaSoftwareModuleType smType, final boolean mandatory) { super(); key = new DistributionSetTypeElementCompositeKey(dsType, smType); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTypeElementCompositeKey.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DistributionSetTypeElementCompositeKey.java similarity index 89% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTypeElementCompositeKey.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DistributionSetTypeElementCompositeKey.java index 2ee1aba0d..f94a3784a 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTypeElementCompositeKey.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DistributionSetTypeElementCompositeKey.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.io.Serializable; @@ -40,7 +40,7 @@ public class DistributionSetTypeElementCompositeKey implements Serializable { * @param smType * in the key */ - DistributionSetTypeElementCompositeKey(final DistributionSetType dsType, final SoftwareModuleType smType) { + DistributionSetTypeElementCompositeKey(final JpaDistributionSetType dsType, final JpaSoftwareModuleType smType) { super(); this.dsType = dsType.getId(); this.smType = smType.getId(); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DsMetadataCompositeKey.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DsMetadataCompositeKey.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DsMetadataCompositeKey.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DsMetadataCompositeKey.java index adc37d65a..52ad217c0 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DsMetadataCompositeKey.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DsMetadataCompositeKey.java @@ -6,10 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.io.Serializable; +import org.eclipse.hawkbit.repository.model.DistributionSet; + /** * The DistributionSet Metadata composite key which contains the meta data key * and the ID of the DistributionSet itself. diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/EntityPropertyChangeListener.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java similarity index 78% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/EntityPropertyChangeListener.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java index 28b5e677c..2dd0fdb40 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/EntityPropertyChangeListener.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java @@ -6,23 +6,23 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus; +package org.eclipse.hawkbit.repository.jpa.model; import java.util.Map; import java.util.stream.Collectors; -import org.eclipse.hawkbit.eventbus.event.AbstractPropertyChangeEvent; -import org.eclipse.hawkbit.eventbus.event.ActionCreatedEvent; -import org.eclipse.hawkbit.eventbus.event.ActionPropertyChangeEvent; -import org.eclipse.hawkbit.eventbus.event.RolloutGroupPropertyChangeEvent; -import org.eclipse.hawkbit.eventbus.event.RolloutPropertyChangeEvent; -import org.eclipse.hawkbit.executor.AfterTransactionCommitExecutor; +import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutPropertyChangeEvent; +import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; -import org.eclipse.hawkbit.repository.model.helper.AfterTransactionCommitExecutorHolder; -import org.eclipse.hawkbit.repository.model.helper.EventBusHolder; import org.eclipse.persistence.descriptors.DescriptorEvent; import org.eclipse.persistence.descriptors.DescriptorEventAdapter; import org.eclipse.persistence.internal.sessions.ObjectChangeSet; @@ -52,13 +52,13 @@ public class EntityPropertyChangeListener extends DescriptorEventAdapter { @Override public void postUpdate(final DescriptorEvent event) { - if (event.getObject().getClass().equals(Action.class)) { + if (event.getObject().getClass().equals(JpaAction.class)) { getAfterTransactionCommmitExecutor().afterCommit(() -> getEventBus().post( new ActionPropertyChangeEvent((Action) event.getObject(), getChangeSet(Action.class, event)))); - } else if (event.getObject().getClass().equals(Rollout.class)) { + } else if (event.getObject().getClass().equals(JpaRollout.class)) { getAfterTransactionCommmitExecutor().afterCommit(() -> getEventBus().post( new RolloutPropertyChangeEvent((Rollout) event.getObject(), getChangeSet(Rollout.class, event)))); - } else if (event.getObject().getClass().equals(RolloutGroup.class)) { + } else if (event.getObject().getClass().equals(JpaRolloutGroup.class)) { getAfterTransactionCommmitExecutor().afterCommit( () -> getEventBus().post(new RolloutGroupPropertyChangeEvent((RolloutGroup) event.getObject(), getChangeSet(RolloutGroup.class, event)))); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java new file mode 100644 index 000000000..5fa2c3bed --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java @@ -0,0 +1,174 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.model; + +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.NamedEntityGraphs; +import javax.persistence.NamedSubgraph; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.persistence.annotations.CascadeOnDelete; + +/** + * JPA implementation of {@link Action}. + */ +@Table(name = "sp_action", indexes = { @Index(name = "sp_idx_action_01", columnList = "tenant,distribution_set"), + @Index(name = "sp_idx_action_02", columnList = "tenant,target,active"), + @Index(name = "sp_idx_action_prim", columnList = "tenant,id") }) +@NamedEntityGraphs({ @NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }), + @NamedEntityGraph(name = "Action.all", attributeNodes = { @NamedAttributeNode("distributionSet"), + @NamedAttributeNode(value = "target", subgraph = "target.ds") }, subgraphs = @NamedSubgraph(name = "target.ds", attributeNodes = @NamedAttributeNode("assignedDistributionSet"))) }) +@Entity +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action { + private static final long serialVersionUID = 1L; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_ds")) + private JpaDistributionSet distributionSet; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_target")) + private JpaTarget target; + + @Column(name = "active") + private boolean active; + + @Column(name = "action_type", nullable = false) + @Enumerated(EnumType.STRING) + private ActionType actionType; + + @Column(name = "forced_time") + private long forcedTime; + + @Column(name = "status") + private Status status; + + @CascadeOnDelete + @OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = { + CascadeType.REMOVE }) + private List actionStatus; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "rolloutgroup", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup")) + private JpaRolloutGroup rolloutGroup; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout")) + private JpaRollout rollout; + + @Override + public DistributionSet getDistributionSet() { + return distributionSet; + } + + @Override + public void setDistributionSet(final DistributionSet distributionSet) { + this.distributionSet = (JpaDistributionSet) distributionSet; + } + + public void setActive(final boolean active) { + this.active = active; + } + + @Override + public Status getStatus() { + return status; + } + + @Override + public void setStatus(final Status status) { + this.status = status; + } + + @Override + public boolean isActive() { + return active; + } + + public void setActionType(final ActionType actionType) { + this.actionType = actionType; + } + + @Override + public ActionType getActionType() { + return actionType; + } + + @Override + public List getActionStatus() { + return actionStatus; + } + + @Override + public void setTarget(final Target target) { + this.target = (JpaTarget) target; + } + + @Override + public Target getTarget() { + return target; + } + + @Override + public long getForcedTime() { + return forcedTime; + } + + public void setForcedTime(final long forcedTime) { + this.forcedTime = forcedTime; + } + + @Override + public RolloutGroup getRolloutGroup() { + return rolloutGroup; + } + + public void setRolloutGroup(final RolloutGroup rolloutGroup) { + this.rolloutGroup = (JpaRolloutGroup) rolloutGroup; + } + + @Override + public Rollout getRollout() { + return rollout; + } + + public void setRollout(final Rollout rollout) { + this.rollout = (JpaRollout) rollout; + } + + @Override + public String toString() { + return "Action [distributionSet=" + distributionSet + ", getId()=" + getId() + "]"; + } + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ActionStatus.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaActionStatus.java similarity index 73% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ActionStatus.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaActionStatus.java index c8d320abd..3a8cb8683 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ActionStatus.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaActionStatus.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.util.ArrayList; import java.util.List; @@ -24,8 +24,13 @@ import javax.persistence.ManyToOne; import javax.persistence.NamedAttributeNode; import javax.persistence.NamedEntityGraph; import javax.persistence.Table; +import javax.persistence.Transient; +import org.eclipse.hawkbit.repository.jpa.cache.CacheField; +import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys; +import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.persistence.annotations.CascadeOnDelete; import com.google.common.base.Splitter; @@ -38,7 +43,10 @@ import com.google.common.base.Splitter; @Index(name = "sp_idx_action_status_prim", columnList = "tenant,id") }) @NamedEntityGraph(name = "ActionStatus.withMessages", attributeNodes = { @NamedAttributeNode("messages") }) @Entity -public class ActionStatus extends TenantAwareBaseEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements ActionStatus { private static final long serialVersionUID = 1L; @Column(name = "target_occurred_at") @@ -46,7 +54,7 @@ public class ActionStatus extends TenantAwareBaseEntity { @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "action", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_act_stat_action")) - private Action action; + private JpaAction action; @Column(name = "status") private Status status; @@ -58,6 +66,13 @@ public class ActionStatus extends TenantAwareBaseEntity { @Column(name = "detail_message", length = 512) private final List messages = new ArrayList<>(); + /** + * Note: filled only in {@link Status#DOWNLOAD}. + */ + @Transient + @CacheField(key = CacheKeys.DOWNLOAD_PROGRESS_PERCENT) + private int downloadProgressPercent; + /** * Creates a new {@link ActionStatus} object. * @@ -68,8 +83,8 @@ public class ActionStatus extends TenantAwareBaseEntity { * @param occurredAt * the occurred timestamp */ - public ActionStatus(final Action action, final Status status, final Long occurredAt) { - this.action = action; + public JpaActionStatus(final Action action, final Status status, final Long occurredAt) { + this.action = (JpaAction) action; this.status = status; this.occurredAt = occurredAt; } @@ -86,56 +101,63 @@ public class ActionStatus extends TenantAwareBaseEntity { * @param messages * the messages which should be added to this action status */ - public ActionStatus(final Action action, final Status status, final Long occurredAt, final String... messages) { + public JpaActionStatus(final JpaAction action, final Status status, final Long occurredAt, final String message) { this.action = action; this.status = status; this.occurredAt = occurredAt; - for (final String msg : messages) { - addMessage(msg); - } + addMessage(message); } /** * JPA default constructor. */ - public ActionStatus() { + public JpaActionStatus() { // JPA default constructor. } + @Override + public int getDownloadProgressPercent() { + return downloadProgressPercent; + } + + @Override public Long getOccurredAt() { return occurredAt; } + @Override public void setOccurredAt(final Long occurredAt) { this.occurredAt = occurredAt; } - /** - * Adds message including splitting in case it exceeds 512 length. - * - * @param message - * to add - */ + @Override public final void addMessage(final String message) { - Splitter.fixedLength(512).split(message).forEach(messages::add); + if (message != null) { + Splitter.fixedLength(512).split(message).forEach(messages::add); + } } + @Override public List getMessages() { return messages; } + @Override public Action getAction() { return action; } + @Override public void setAction(final Action action) { - this.action = action; + this.action = (JpaAction) action; } + @Override public Status getStatus() { return status; } + @Override public void setStatus(final Status status) { this.status = status; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ActionWithStatusCount.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaActionWithStatusCount.java similarity index 64% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ActionWithStatusCount.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaActionWithStatusCount.java index 73eab32f9..32b01cbe2 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ActionWithStatusCount.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaActionWithStatusCount.java @@ -6,29 +6,25 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; +import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.ActionWithStatusCount; /** * Custom JPA Model for querying {@link Action} include the count of the * action's {@link ActionStatus}. * */ -public class ActionWithStatusCount { +public class JpaActionWithStatusCount implements ActionWithStatusCount { private final Long actionStatusCount; - private final Long actionId; - private final ActionType actionType; - private final boolean actionActive; - private final long actionForceTime; - private final Status actionStatus; - private final Long actionCreatedAt; - private final Long actionLastModifiedAt; private final Long dsId; private final String dsName; private final String dsVersion; - private final Action action; + private final JpaAction action; private final String rolloutName; /** @@ -60,82 +56,57 @@ public class ActionWithStatusCount { * @param rolloutName * the rollout name */ - - public ActionWithStatusCount(final Long actionId, final ActionType actionType, final boolean active, + // Exception squid:S00107 - needed this way for JPA to fill the view + @SuppressWarnings("squid:S00107") + public JpaActionWithStatusCount(final Long actionId, final ActionType actionType, final boolean active, final long forcedTime, final Status status, final Long actionCreatedAt, final Long actionLastModifiedAt, final Long dsId, final String dsName, final String dsVersion, final Long actionStatusCount, final String rolloutName) { - this.actionId = actionId; - this.actionType = actionType; - actionActive = active; - actionForceTime = forcedTime; - actionStatus = status; - this.actionCreatedAt = actionCreatedAt; - this.actionLastModifiedAt = actionLastModifiedAt; this.dsId = dsId; this.dsName = dsName; this.dsVersion = dsVersion; this.actionStatusCount = actionStatusCount; this.rolloutName = rolloutName; - action = new Action(); + action = new JpaAction(); action.setActionType(actionType); - action.setActive(actionActive); - action.setForcedTime(actionForceTime); - action.setStatus(actionStatus); + action.setActive(active); + action.setForcedTime(forcedTime); + action.setStatus(status); action.setId(actionId); + action.setActionType(actionType); + action.setCreatedAt(actionCreatedAt); + action.setLastModifiedAt(actionLastModifiedAt); + } + @Override public Action getAction() { return action; } - public Long getActionId() { - return actionId; - } - - public ActionType getActionType() { - return actionType; - } - - public boolean isActionActive() { - return actionActive; - } - - public long getActionForceTime() { - return actionForceTime; - } - - public Status getActionStatus() { - return actionStatus; - } - - public Long getActionCreatedAt() { - return actionCreatedAt; - } - - public Long getActionLastModifiedAt() { - return actionLastModifiedAt; - } - + @Override public Long getDsId() { return dsId; } + @Override public String getDsName() { return dsName; } + @Override public String getDsVersion() { return dsVersion; } + @Override public Long getActionStatusCount() { return actionStatusCount; } + @Override public String getRolloutName() { return rolloutName; } - } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSet.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java similarity index 79% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSet.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java index a9d390284..676215424 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSet.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java @@ -6,9 +6,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -34,17 +35,19 @@ import javax.persistence.UniqueConstraint; import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException; import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.persistence.annotations.CascadeOnDelete; /** - *

- * The {@link DistributionSet} is defined in the SP repository and contains at - * least an OS and an Agent Hub. - *

- * - *

- * A {@link Target} has exactly one target {@link DistributionSet} assigned. - *

+ * Jpa implementation of {@link DistributionSet}. * */ @Entity @@ -55,52 +58,56 @@ import org.eclipse.persistence.annotations.CascadeOnDelete; @Index(name = "sp_idx_distribution_set_prim", columnList = "tenant,id") }) @NamedEntityGraph(name = "DistributionSet.detail", attributeNodes = { @NamedAttributeNode("modules"), @NamedAttributeNode("tags"), @NamedAttributeNode("type") }) -public class DistributionSet extends NamedVersionedEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implements DistributionSet { private static final long serialVersionUID = 1L; @Column(name = "required_migration_step") - private boolean requiredMigrationStep = false; + private boolean requiredMigrationStep; - @ManyToMany(targetEntity = SoftwareModule.class, fetch = FetchType.LAZY) + @ManyToMany(targetEntity = JpaSoftwareModule.class, fetch = FetchType.LAZY) @JoinTable(name = "sp_ds_module", joinColumns = { @JoinColumn(name = "ds_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_ds")) }, inverseJoinColumns = { @JoinColumn(name = "module_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_module")) }) private final Set modules = new HashSet<>(); - @ManyToMany(targetEntity = DistributionSetTag.class) + @ManyToMany(targetEntity = JpaDistributionSetTag.class) @JoinTable(name = "sp_ds_dstag", joinColumns = { @JoinColumn(name = "ds", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_ds")) }, inverseJoinColumns = { @JoinColumn(name = "TAG", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_tag")) }) private Set tags = new HashSet<>(); @Column(name = "deleted") - private boolean deleted = false; + private boolean deleted; - @OneToMany(mappedBy = "assignedDistributionSet", targetEntity = Target.class, fetch = FetchType.LAZY) + @OneToMany(mappedBy = "assignedDistributionSet", targetEntity = JpaTarget.class, fetch = FetchType.LAZY) private List assignedToTargets; - @OneToMany(mappedBy = "installedDistributionSet", targetEntity = TargetInfo.class, fetch = FetchType.LAZY) + @OneToMany(mappedBy = "installedDistributionSet", targetEntity = JpaTargetInfo.class, fetch = FetchType.LAZY) private List installedAtTargets; - @OneToMany(mappedBy = "distributionSet", targetEntity = Action.class, fetch = FetchType.LAZY) + @OneToMany(mappedBy = "distributionSet", targetEntity = JpaAction.class, fetch = FetchType.LAZY) private List actions; @CascadeOnDelete - @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE }) + @OneToMany(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetMetadata.class, cascade = { + CascadeType.REMOVE }) @JoinColumn(name = "ds_id", insertable = false, updatable = false) private final List metadata = new ArrayList<>(); - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetType.class) @JoinColumn(name = "ds_id", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstype_ds")) private DistributionSetType type; @Column(name = "complete") - private boolean complete = false; + private boolean complete; /** * Default constructor. */ - public DistributionSet() { + public JpaDistributionSet() { super(); } @@ -118,8 +125,8 @@ public class DistributionSet extends NamedVersionedEntity { * @param moduleList * {@link SoftwareModule}s of the {@link DistributionSet} */ - public DistributionSet(final String name, final String version, final String description, - final DistributionSetType type, final Iterable moduleList) { + public JpaDistributionSet(final String name, final String version, final String description, + final DistributionSetType type, final Collection moduleList) { super(name, version, description); this.type = type; @@ -131,17 +138,17 @@ public class DistributionSet extends NamedVersionedEntity { } } + @Override public Set getTags() { return tags; } + @Override public boolean isDeleted() { return deleted; } - /** - * @return immutable list of meta data elements. - */ + @Override public List getMetadata() { return Collections.unmodifiableList(metadata); } @@ -150,15 +157,18 @@ public class DistributionSet extends NamedVersionedEntity { return actions; } + @Override public boolean isRequiredMigrationStep() { return requiredMigrationStep; } + @Override public DistributionSet setDeleted(final boolean deleted) { this.deleted = deleted; return this; } + @Override public DistributionSet setRequiredMigrationStep(final boolean isRequiredMigrationStep) { requiredMigrationStep = isRequiredMigrationStep; return this; @@ -169,16 +179,12 @@ public class DistributionSet extends NamedVersionedEntity { return this; } - /** - * @return the assignedTargets - */ + @Override public List getAssignedTargets() { return assignedToTargets; } - /** - * @return the installedTargets - */ + @Override public List getInstalledTargets() { return installedAtTargets; } @@ -189,24 +195,12 @@ public class DistributionSet extends NamedVersionedEntity { + ", getId()=" + getId() + "]"; } - /** - * - * @return unmodifiableSet of {@link SoftwareModule}. - */ + @Override public Set getModules() { return Collections.unmodifiableSet(modules); } - public DistributionSetIdName getDistributionSetIdName() { - return new DistributionSetIdName(getId(), getName(), getVersion()); - } - - /** - * @param softwareModule - * @return true if the module was added and false - * if it already existed in the set - * - */ + @Override public boolean addModule(final SoftwareModule softwareModule) { // we cannot allow that modules are added without a type defined @@ -243,13 +237,7 @@ public class DistributionSet extends NamedVersionedEntity { return false; } - /** - * Removed given {@link SoftwareModule} from this DS instance. - * - * @param softwareModule - * to remove - * @return true if element was found and removed - */ + @Override public boolean removeModule(final SoftwareModule softwareModule) { final Optional found = modules.stream() .filter(module -> module.getId().equals(softwareModule.getId())).findFirst(); @@ -264,14 +252,7 @@ public class DistributionSet extends NamedVersionedEntity { } - /** - * Searches through modules for the given type. - * - * @param type - * to search for - * @return SoftwareModule of given type or null if not in the - * list. - */ + @Override public SoftwareModule findFirstModuleByType(final SoftwareModuleType type) { final Optional result = modules.stream().filter(module -> module.getType().equals(type)) .findFirst(); @@ -283,15 +264,19 @@ public class DistributionSet extends NamedVersionedEntity { return null; } + @Override public DistributionSetType getType() { return type; } + @Override public void setType(final DistributionSetType type) { this.type = type; } + @Override public boolean isComplete() { return complete; } + } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetMetadata.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetMetadata.java similarity index 70% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetMetadata.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetMetadata.java index 67a99506c..3f4323bbe 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetMetadata.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetMetadata.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.ConstraintMode; import javax.persistence.Entity; @@ -18,6 +18,9 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; + /** * Meta data for {@link DistributionSet}. * @@ -25,21 +28,21 @@ import javax.persistence.Table; @IdClass(DsMetadataCompositeKey.class) @Entity @Table(name = "sp_ds_metadata") -public class DistributionSetMetadata extends MetaData { +public class JpaDistributionSetMetadata extends AbstractJpaMetaData implements DistributionSetMetadata { private static final long serialVersionUID = 1L; @Id @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "ds_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_metadata_ds")) - private DistributionSet distributionSet; + private JpaDistributionSet distributionSet; - public DistributionSetMetadata() { + public JpaDistributionSetMetadata() { // default public constructor for JPA } - public DistributionSetMetadata(final String key, final DistributionSet distributionSet, final String value) { + public JpaDistributionSetMetadata(final String key, final DistributionSet distributionSet, final String value) { super(key, value); - this.distributionSet = distributionSet; + this.distributionSet = (JpaDistributionSet) distributionSet; } public DsMetadataCompositeKey getId() { @@ -47,9 +50,10 @@ public class DistributionSetMetadata extends MetaData { } public void setDistributionSet(final DistributionSet distributionSet) { - this.distributionSet = distributionSet; + this.distributionSet = (JpaDistributionSet) distributionSet; } + @Override public DistributionSet getDistributionSet() { return distributionSet; } @@ -63,11 +67,13 @@ public class DistributionSetMetadata extends MetaData { } @Override + // exception squid:S2259 - obj is checked for null in super + @SuppressWarnings("squid:S2259") public boolean equals(final Object obj) { if (!super.equals(obj)) { return false; } - final DistributionSetMetadata other = (DistributionSetMetadata) obj; + final JpaDistributionSetMetadata other = (JpaDistributionSetMetadata) obj; if (distributionSet == null) { if (other.distributionSet != null) { return false; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTag.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetTag.java similarity index 76% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTag.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetTag.java index 137fde5b9..1663fb620 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTag.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetTag.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.util.List; @@ -17,6 +17,9 @@ import javax.persistence.ManyToMany; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; + /** * A {@link DistributionSetTag} is used to describe DistributionSet attributes * and use them also for filtering the DistributionSet list. @@ -26,10 +29,10 @@ import javax.persistence.UniqueConstraint; @Table(name = "sp_distributionset_tag", indexes = { @Index(name = "sp_idx_distribution_set_tag_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_ds_tag")) -public class DistributionSetTag extends Tag { +public class JpaDistributionSetTag extends AbstractJpaTag implements DistributionSetTag { private static final long serialVersionUID = 1L; - @ManyToMany(mappedBy = "tags", targetEntity = DistributionSet.class, fetch = FetchType.LAZY) + @ManyToMany(mappedBy = "tags", targetEntity = JpaDistributionSet.class, fetch = FetchType.LAZY) private List assignedToDistributionSet; /** @@ -38,7 +41,7 @@ public class DistributionSetTag extends Tag { * @param name * of the {@link DistributionSetTag} **/ - public DistributionSetTag(final String name) { + public JpaDistributionSetTag(final String name) { super(name, null, null); } @@ -52,14 +55,18 @@ public class DistributionSetTag extends Tag { * @param colour * of tag in UI */ - public DistributionSetTag(final String name, final String description, final String colour) { + public JpaDistributionSetTag(final String name, final String description, final String colour) { super(name, description, colour); } - DistributionSetTag() { - super(); + /** + * Default constructor for JPA. + */ + public JpaDistributionSetTag() { + // Default constructor for JPA. } + @Override public List getAssignedToDistributionSet() { return assignedToDistributionSet; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetType.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetType.java similarity index 50% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetType.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetType.java index 61d2fc58c..54aed44dd 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetType.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetType.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.util.HashSet; import java.util.Optional; @@ -23,6 +23,10 @@ import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; + /** * A distribution set type defines which software module types can or have to be * {@link DistributionSet}. @@ -34,7 +38,10 @@ import javax.persistence.UniqueConstraint; @Index(name = "sp_idx_distribution_set_type_prim", columnList = "tenant,id") }, uniqueConstraints = { @UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_dst_name"), @UniqueConstraint(columnNames = { "type_key", "tenant" }, name = "uk_dst_key") }) -public class DistributionSetType extends NamedEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaDistributionSetType extends AbstractJpaNamedEntity implements DistributionSetType { private static final long serialVersionUID = 1L; @OneToMany(targetEntity = DistributionSetTypeElement.class, cascade = { @@ -49,9 +56,9 @@ public class DistributionSetType extends NamedEntity { private String colour; @Column(name = "deleted") - private boolean deleted = false; + private boolean deleted; - public DistributionSetType() { + public JpaDistributionSetType() { // default public constructor for JPA } @@ -65,7 +72,7 @@ public class DistributionSetType extends NamedEntity { * @param description * of the type */ - public DistributionSetType(final String key, final String name, final String description) { + public JpaDistributionSetType(final String key, final String name, final String description) { this(key, name, description, null); } @@ -81,162 +88,53 @@ public class DistributionSetType extends NamedEntity { * @param color * of the type. It will be null by default */ - public DistributionSetType(final String key, final String name, final String description, final String color) { + public JpaDistributionSetType(final String key, final String name, final String description, final String color) { super(name, description); this.key = key; colour = color; } - /** - * @return the deleted - */ + @Override public boolean isDeleted() { return deleted; } - /** - * @param deleted - * the deleted to set - */ public void setDeleted(final boolean deleted) { this.deleted = deleted; } + @Override public Set getMandatoryModuleTypes() { return elements.stream().filter(element -> element.isMandatory()).map(element -> element.getSmType()) .collect(Collectors.toSet()); } + @Override public Set getOptionalModuleTypes() { return elements.stream().filter(element -> !element.isMandatory()).map(element -> element.getSmType()) .collect(Collectors.toSet()); } - /** - * Checks if the given {@link SoftwareModuleType} is in this - * {@link DistributionSetType}. - * - * @param softwareModuleType - * search for - * @return true if found - */ - public boolean containsModuleType(final SoftwareModuleType softwareModuleType) { - for (final DistributionSetTypeElement distributionSetTypeElement : elements) { - if (distributionSetTypeElement.getSmType().equals(softwareModuleType)) { - return true; - } - - } - return false; - } - - /** - * Checks if the given {@link SoftwareModuleType} is in this - * {@link DistributionSetType} and defined as - * {@link DistributionSetTypeElement#isMandatory()}. - * - * @param softwareModuleType - * search for - * @return true if found - */ - public boolean containsMandatoryModuleType(final SoftwareModuleType softwareModuleType) { - return elements.stream().filter(element -> element.isMandatory()) - .filter(element -> element.getSmType().equals(softwareModuleType)).findFirst().isPresent(); - - } - - /** - * Checks if the given {@link SoftwareModuleType} is in this - * {@link DistributionSetType} and defined as - * {@link DistributionSetTypeElement#isMandatory()}. - * - * @param softwareModuleType - * search for by {@link SoftwareModuleType#getId()} - * @return true if found - */ - public boolean containsMandatoryModuleType(final Long softwareModuleTypeId) { - return elements.stream().filter(element -> element.isMandatory()) - .filter(element -> element.getSmType().getId().equals(softwareModuleTypeId)).findFirst().isPresent(); - - } - - /** - * Checks if the given {@link SoftwareModuleType} is in this - * {@link DistributionSetType} and NOT defined as - * {@link DistributionSetTypeElement#isMandatory()}. - * - * @param softwareModuleType - * search for - * @return true if found - */ - public boolean containsOptionalModuleType(final SoftwareModuleType softwareModuleType) { - return elements.stream().filter(element -> !element.isMandatory()) - .filter(element -> element.getSmType().equals(softwareModuleType)).findFirst().isPresent(); - - } - - /** - * Checks if the given {@link SoftwareModuleType} is in this - * {@link DistributionSetType} and NOT defined as - * {@link DistributionSetTypeElement#isMandatory()}. - * - * @param softwareModuleTypeId - * search by {@link SoftwareModuleType#getId()} - * @return true if found - */ - public boolean containsOptionalModuleType(final Long softwareModuleTypeId) { - return elements.stream().filter(element -> !element.isMandatory()) - .filter(element -> element.getSmType().getId().equals(softwareModuleTypeId)).findFirst().isPresent(); - - } - - /** - * Compares the modules of this {@link DistributionSetType} and the given - * one. - * - * @param dsType - * to compare with - * @return true if the lists are identical. - */ + @Override public boolean areModuleEntriesIdentical(final DistributionSetType dsType) { - return new HashSet(dsType.elements).equals(elements); + return new HashSet(((JpaDistributionSetType) dsType).elements).equals(elements); } - /** - * Adds {@link SoftwareModuleType} that is optional for the - * {@link DistributionSet}. - * - * @param smType - * to add - * @return updated instance - */ + @Override public DistributionSetType addOptionalModuleType(final SoftwareModuleType smType) { - elements.add(new DistributionSetTypeElement(this, smType, false)); + elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, false)); return this; } - /** - * Adds {@link SoftwareModuleType} that is mandatory for the - * {@link DistributionSet}. - * - * @param smType - * to add - * @return updated instance - */ + @Override public DistributionSetType addMandatoryModuleType(final SoftwareModuleType smType) { - elements.add(new DistributionSetTypeElement(this, smType, true)); + elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, true)); return this; } - /** - * Removes {@link SoftwareModuleType} from the list. - * - * @param smTypeId - * to remove - * @return updated instance - */ + @Override public DistributionSetType removeModuleType(final Long smTypeId) { // we search by id (standard equals compares also revison) final Optional found = elements.stream() @@ -249,29 +147,28 @@ public class DistributionSetType extends NamedEntity { return this; } + @Override public String getKey() { return key; } + @Override public void setKey(final String key) { this.key = key; } - /** - * @param distributionSet - * to check for completeness - * @return true if the all mandatory software module types are - * in the system. - */ + @Override public boolean checkComplete(final DistributionSet distributionSet) { return distributionSet.getModules().stream().map(module -> module.getType()).collect(Collectors.toList()) .containsAll(getMandatoryModuleTypes()); } + @Override public String getColour() { return colour; } + @Override public void setColour(final String colour) { this.colour = colour; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifact.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaExternalArtifact.java similarity index 76% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifact.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaExternalArtifact.java index 898c685a5..b8408cdcc 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifact.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaExternalArtifact.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.net.URL; @@ -21,6 +21,10 @@ import javax.persistence.ManyToOne; import javax.persistence.Table; import javax.validation.constraints.NotNull; +import org.eclipse.hawkbit.repository.model.ExternalArtifact; +import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider; +import org.eclipse.hawkbit.repository.model.SoftwareModule; + /** * External artifact representation with all the necessary information to * generate an artifact {@link URL} at runtime. @@ -29,12 +33,15 @@ import javax.validation.constraints.NotNull; @Table(name = "sp_external_artifact", indexes = { @Index(name = "sp_idx_external_artifact_prim", columnList = "id,tenant") }) @Entity -public class ExternalArtifact extends Artifact { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaExternalArtifact extends AbstractJpaArtifact implements ExternalArtifact { private static final long serialVersionUID = 1L; @ManyToOne @JoinColumn(name = "provider", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_art_to_ext_provider")) - private ExternalArtifactProvider externalArtifactProvider; + private JpaExternalArtifactProvider externalArtifactProvider; @Column(name = "url_suffix", length = 512) private String urlSuffix; @@ -42,12 +49,12 @@ public class ExternalArtifact extends Artifact { // CascadeType.PERSIST as we register ourself at the BSM @ManyToOne(optional = false, cascade = { CascadeType.PERSIST }) @JoinColumn(name = "software_module", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_external_assigned_sm")) - private SoftwareModule softwareModule; + private JpaSoftwareModule softwareModule; /** * Default constructor. */ - public ExternalArtifact() { + public JpaExternalArtifact() { super(); } @@ -61,10 +68,10 @@ public class ExternalArtifact extends Artifact { * @param softwareModule * of the artifact */ - public ExternalArtifact(@NotNull final ExternalArtifactProvider externalArtifactProvider, final String urlSuffix, + public JpaExternalArtifact(@NotNull final ExternalArtifactProvider externalArtifactProvider, final String urlSuffix, final SoftwareModule softwareModule) { setSoftwareModule(softwareModule); - this.externalArtifactProvider = externalArtifactProvider; + this.externalArtifactProvider = (JpaExternalArtifactProvider) externalArtifactProvider; if (urlSuffix != null) { this.urlSuffix = urlSuffix; @@ -82,23 +89,26 @@ public class ExternalArtifact extends Artifact { } public final void setSoftwareModule(final SoftwareModule softwareModule) { - this.softwareModule = softwareModule; + this.softwareModule = (JpaSoftwareModule) softwareModule; this.softwareModule.addArtifact(this); } + @Override public ExternalArtifactProvider getExternalArtifactProvider() { return externalArtifactProvider; } + @Override public String getUrl() { return new StringBuilder().append(externalArtifactProvider.getBasePath()).append(urlSuffix).toString(); } + @Override public String getUrlSuffix() { return urlSuffix; } - public void setExternalArtifactProvider(final ExternalArtifactProvider externalArtifactProvider) { + public void setExternalArtifactProvider(final JpaExternalArtifactProvider externalArtifactProvider) { this.externalArtifactProvider = externalArtifactProvider; } @@ -106,6 +116,7 @@ public class ExternalArtifact extends Artifact { * @param urlSuffix * the urlSuffix to set */ + @Override public void setUrlSuffix(final String urlSuffix) { this.urlSuffix = urlSuffix; } @@ -123,7 +134,7 @@ public class ExternalArtifact extends Artifact { if (!super.equals(obj)) { return false; } - if (!(obj instanceof ExternalArtifact)) { + if (!(obj instanceof JpaExternalArtifact)) { return false; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifactProvider.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaExternalArtifactProvider.java similarity index 73% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifactProvider.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaExternalArtifactProvider.java index 9fa8714ac..7a4e2a067 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifactProvider.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaExternalArtifactProvider.java @@ -6,23 +6,27 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Index; import javax.persistence.Table; +import org.eclipse.hawkbit.repository.model.ExternalArtifact; +import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider; + /** - * External repositories for artifact storage. The SP server provides URLs for - * the targets to download from these external resources but does not access - * them itself. + * JPA implementation of {@link ExternalArtifactProvider}. * */ @Table(name = "sp_external_provider", indexes = { @Index(name = "sp_idx_external_provider_prim", columnList = "tenant,id") }) @Entity -public class ExternalArtifactProvider extends NamedEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaExternalArtifactProvider extends AbstractJpaNamedEntity implements ExternalArtifactProvider { private static final long serialVersionUID = 1L; @Column(name = "base_url", length = 512, nullable = false) @@ -44,31 +48,35 @@ public class ExternalArtifactProvider extends NamedEntity { * that is used if {@link ExternalArtifact#getUrlSuffix()} is * empty. */ - public ExternalArtifactProvider(final String name, final String description, final String baseURL, + public JpaExternalArtifactProvider(final String name, final String description, final String baseURL, final String defaultUrlSuffix) { super(name, description); basePath = baseURL; defaultSuffix = defaultUrlSuffix; } - ExternalArtifactProvider() { + JpaExternalArtifactProvider() { super(); defaultSuffix = ""; basePath = ""; } + @Override public String getBasePath() { return basePath; } + @Override public String getDefaultSuffix() { return defaultSuffix; } + @Override public void setBasePath(final String basePath) { this.basePath = basePath; } + @Override public void setDefaultSuffix(final String defaultSuffix) { this.defaultSuffix = defaultSuffix; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/LocalArtifact.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaLocalArtifact.java similarity index 80% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/LocalArtifact.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaLocalArtifact.java index 8afcdc168..52cc01b20 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/LocalArtifact.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaLocalArtifact.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.CascadeType; import javax.persistence.Column; @@ -19,22 +19,23 @@ import javax.persistence.ManyToOne; import javax.persistence.Table; import javax.validation.constraints.NotNull; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.SoftwareModule; + import com.mongodb.gridfs.GridFS; import com.mongodb.gridfs.GridFSFile; /** - * Tenant specific locally stored artifact representation that is used by - * {@link SoftwareModule} . It contains all information that is provided by the - * user while all SP server generated information related to the artifact (hash, - * length) is stored directly with the binary itself. - * - * + * JPA implementation of {@link LocalArtifact}. * */ @Table(name = "sp_artifact", indexes = { @Index(name = "sp_idx_artifact_01", columnList = "tenant,software_module"), @Index(name = "sp_idx_artifact_prim", columnList = "tenant,id") }) @Entity -public class LocalArtifact extends Artifact { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaLocalArtifact extends AbstractJpaArtifact implements LocalArtifact { private static final long serialVersionUID = 1L; @NotNull @@ -47,12 +48,12 @@ public class LocalArtifact extends Artifact { @ManyToOne(optional = false, cascade = { CascadeType.PERSIST }) @JoinColumn(name = "software_module", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_assigned_sm")) - private SoftwareModule softwareModule; + private JpaSoftwareModule softwareModule; /** * Default constructor. */ - public LocalArtifact() { + public JpaLocalArtifact() { super(); } @@ -66,7 +67,7 @@ public class LocalArtifact extends Artifact { * @param softwareModule * of this artifact */ - public LocalArtifact(@NotNull final String gridFsFileName, @NotNull final String filename, + public JpaLocalArtifact(@NotNull final String gridFsFileName, @NotNull final String filename, final SoftwareModule softwareModule) { setSoftwareModule(softwareModule); this.gridFsFileName = gridFsFileName; @@ -99,7 +100,7 @@ public class LocalArtifact extends Artifact { } public final void setSoftwareModule(final SoftwareModule softwareModule) { - this.softwareModule = softwareModule; + this.softwareModule = (JpaSoftwareModule) softwareModule; this.softwareModule.addArtifact(this); } @@ -107,6 +108,7 @@ public class LocalArtifact extends Artifact { return gridFsFileName; } + @Override public String getFilename() { return filename; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Rollout.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java similarity index 77% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Rollout.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java index a7f9b10cb..3cbe65717 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Rollout.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.util.List; @@ -25,23 +25,30 @@ import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.UniqueConstraint; -import org.eclipse.hawkbit.cache.CacheField; -import org.eclipse.hawkbit.cache.CacheKeys; +import org.eclipse.hawkbit.repository.jpa.cache.CacheField; +import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys; import org.eclipse.hawkbit.repository.model.Action.ActionType; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; /** - * @author Michael Hirsch + * JPA implementation of a {@link Rollout}. * */ @Entity @Table(name = "sp_rollout", indexes = { @Index(name = "sp_idx_rollout_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_rollout")) -public class Rollout extends NamedEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaRollout extends AbstractJpaNamedEntity implements Rollout { private static final long serialVersionUID = 1L; - @OneToMany(targetEntity = RolloutGroup.class) + @OneToMany(targetEntity = JpaRolloutGroup.class) @JoinColumn(name = "rollout", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollout_rolloutgroup")) private List rolloutGroups; @@ -50,13 +57,13 @@ public class Rollout extends NamedEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolltout_ds")) - private DistributionSet distributionSet; + private JpaDistributionSet distributionSet; @Column(name = "status") private RolloutStatus status = RolloutStatus.CREATING; @Column(name = "last_check") - private long lastCheck = 0L; + private long lastCheck; @Column(name = "action_type", nullable = false) @Enumerated(EnumType.STRING) @@ -70,23 +77,26 @@ public class Rollout extends NamedEntity { @Transient @CacheField(key = CacheKeys.ROLLOUT_GROUP_TOTAL) - private int rolloutGroupsTotal = 0; + private int rolloutGroupsTotal; @Transient @CacheField(key = CacheKeys.ROLLOUT_GROUP_CREATED) - private int rolloutGroupsCreated = 0; + private int rolloutGroupsCreated; @Transient private transient TotalTargetCountStatus totalTargetCountStatus; + @Override public DistributionSet getDistributionSet() { return distributionSet; } + @Override public void setDistributionSet(final DistributionSet distributionSet) { - this.distributionSet = distributionSet; + this.distributionSet = (JpaDistributionSet) distributionSet; } + @Override public List getRolloutGroups() { return rolloutGroups; } @@ -95,14 +105,17 @@ public class Rollout extends NamedEntity { this.rolloutGroups = rolloutGroups; } + @Override public String getTargetFilterQuery() { return targetFilterQuery; } + @Override public void setTargetFilterQuery(final String targetFilterQuery) { this.targetFilterQuery = targetFilterQuery; } + @Override public RolloutStatus getStatus() { return status; } @@ -119,22 +132,27 @@ public class Rollout extends NamedEntity { this.lastCheck = lastCheck; } + @Override public ActionType getActionType() { return actionType; } + @Override public void setActionType(final ActionType actionType) { this.actionType = actionType; } + @Override public long getForcedTime() { return forcedTime; } + @Override public void setForcedTime(final long forcedTime) { this.forcedTime = forcedTime; } + @Override public long getTotalTargets() { return totalTargets; } @@ -151,6 +169,7 @@ public class Rollout extends NamedEntity { this.rolloutGroupsTotal = rolloutGroupsTotal; } + @Override public int getRolloutGroupsCreated() { return rolloutGroupsCreated; } @@ -159,6 +178,7 @@ public class Rollout extends NamedEntity { this.rolloutGroupsCreated = rolloutGroupsCreated; } + @Override public TotalTargetCountStatus getTotalTargetCountStatus() { if (totalTargetCountStatus == null) { totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); @@ -177,58 +197,4 @@ public class Rollout extends NamedEntity { + ", getName()=" + getName() + ", getId()=" + getId() + "]"; } - /** - * - * State machine for rollout. - * - */ - public enum RolloutStatus { - - /** - * Rollouts is beeing created. - */ - CREATING, - - /** - * Rollout is ready to start. - */ - READY, - - /** - * Rollout is paused. - */ - PAUSED, - - /** - * Rollout is starting. - */ - STARTING, - - /** - * Rollout is stopped. - */ - STOPPED, - - /** - * Rollout is running. - */ - RUNNING, - - /** - * Rollout is finished. - */ - FINISHED, - - /** - * Rollout could not created due errors, might be database problem due - * asynchronous creating. - */ - ERROR_CREATING, - - /** - * Rollout could not started due errors, might be database problem due - * asynchronous starting. - */ - ERROR_STARTING; - } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java new file mode 100644 index 000000000..79da6630a --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java @@ -0,0 +1,239 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.model; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.persistence.UniqueConstraint; + +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; + +/** + * JPA entity definition of persisting a group of an rollout. + * + */ +@Entity +@Table(name = "sp_rolloutgroup", indexes = { + @Index(name = "sp_idx_rolloutgroup_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { + "name", "rollout", "tenant" }, name = "uk_rolloutgroup")) +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup { + + private static final long serialVersionUID = 1L; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolloutgroup_rollout")) + private JpaRollout rollout; + + @Column(name = "status") + private RolloutGroupStatus status = RolloutGroupStatus.READY; + + @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }, targetEntity = RolloutTargetGroup.class) + @JoinColumn(name = "rolloutGroup_Id", insertable = false, updatable = false) + private final List rolloutTargetGroup = new ArrayList<>(); + + @ManyToOne(fetch = FetchType.LAZY) + private JpaRolloutGroup parent; + + @Column(name = "success_condition", nullable = false) + private RolloutGroupSuccessCondition successCondition = RolloutGroupSuccessCondition.THRESHOLD; + + @Column(name = "success_condition_exp", length = 512, nullable = false) + private String successConditionExp; + + @Column(name = "success_action", nullable = false) + private RolloutGroupSuccessAction successAction = RolloutGroupSuccessAction.NEXTGROUP; + + @Column(name = "success_action_exp", length = 512, nullable = false) + private String successActionExp; + + @Column(name = "error_condition") + private RolloutGroupErrorCondition errorCondition; + + @Column(name = "error_condition_exp", length = 512) + private String errorConditionExp; + + @Column(name = "error_action") + private RolloutGroupErrorAction errorAction; + + @Column(name = "error_action_exp", length = 512) + private String errorActionExp; + + @Column(name = "total_targets") + private long totalTargets; + + @Transient + private transient TotalTargetCountStatus totalTargetCountStatus; + + @Override + public Rollout getRollout() { + return rollout; + } + + @Override + public void setRollout(final Rollout rollout) { + this.rollout = (JpaRollout) rollout; + } + + @Override + public RolloutGroupStatus getStatus() { + return status; + } + + @Override + public void setStatus(final RolloutGroupStatus status) { + this.status = status; + } + + public List getRolloutTargetGroup() { + return rolloutTargetGroup; + } + + @Override + public RolloutGroup getParent() { + return parent; + } + + public void setParent(final RolloutGroup parent) { + this.parent = (JpaRolloutGroup) parent; + } + + @Override + public RolloutGroupSuccessCondition getSuccessCondition() { + return successCondition; + } + + @Override + public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) { + successCondition = finishCondition; + } + + @Override + public String getSuccessConditionExp() { + return successConditionExp; + } + + @Override + public void setSuccessConditionExp(final String finishExp) { + successConditionExp = finishExp; + } + + @Override + public RolloutGroupErrorCondition getErrorCondition() { + return errorCondition; + } + + @Override + public void setErrorCondition(final RolloutGroupErrorCondition errorCondition) { + this.errorCondition = errorCondition; + } + + @Override + public String getErrorConditionExp() { + return errorConditionExp; + } + + @Override + public void setErrorConditionExp(final String errorExp) { + errorConditionExp = errorExp; + } + + @Override + public RolloutGroupErrorAction getErrorAction() { + return errorAction; + } + + @Override + public void setErrorAction(final RolloutGroupErrorAction errorAction) { + this.errorAction = errorAction; + } + + @Override + public String getErrorActionExp() { + return errorActionExp; + } + + @Override + public void setErrorActionExp(final String errorActionExp) { + this.errorActionExp = errorActionExp; + } + + @Override + public RolloutGroupSuccessAction getSuccessAction() { + return successAction; + } + + @Override + public String getSuccessActionExp() { + return successActionExp; + } + + @Override + public long getTotalTargets() { + return totalTargets; + } + + public void setTotalTargets(final long totalTargets) { + this.totalTargets = totalTargets; + } + + public void setSuccessAction(final RolloutGroupSuccessAction successAction) { + this.successAction = successAction; + } + + public void setSuccessActionExp(final String successActionExp) { + this.successActionExp = successActionExp; + } + + /** + * @return the totalTargetCountStatus + */ + @Override + public TotalTargetCountStatus getTotalTargetCountStatus() { + if (totalTargetCountStatus == null) { + totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); + } + return totalTargetCountStatus; + } + + /** + * @param totalTargetCountStatus + * the totalTargetCountStatus to set + */ + @Override + public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) { + this.totalTargetCountStatus = totalTargetCountStatus; + } + + @Override + public String toString() { + return "RolloutGroup [rollout=" + rollout + ", status=" + status + ", rolloutTargetGroup=" + rolloutTargetGroup + + ", parent=" + parent + ", finishCondition=" + successCondition + ", finishExp=" + successConditionExp + + ", errorCondition=" + errorCondition + ", errorExp=" + errorConditionExp + ", getName()=" + getName() + + ", getId()=" + getId() + "]"; + } + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModule.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaSoftwareModule.java similarity index 82% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModule.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaSoftwareModule.java index 327bff3db..80156edb8 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModule.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaSoftwareModule.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.util.ArrayList; import java.util.Collections; @@ -29,6 +29,13 @@ import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import org.eclipse.hawkbit.repository.model.Artifact; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.ExternalArtifact; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.persistence.annotations.CascadeOnDelete; /** @@ -43,37 +50,40 @@ import org.eclipse.persistence.annotations.CascadeOnDelete; @Index(name = "sp_idx_base_sw_module_02", columnList = "tenant,deleted,module_type"), @Index(name = "sp_idx_base_sw_module_prim", columnList = "tenant,id") }) @NamedEntityGraph(name = "SoftwareModule.artifacts", attributeNodes = { @NamedAttributeNode("artifacts") }) -public class SoftwareModule extends NamedVersionedEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implements SoftwareModule { private static final long serialVersionUID = 1L; @ManyToOne @JoinColumn(name = "module_type", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_module_type")) - private SoftwareModuleType type; + private JpaSoftwareModuleType type; - @ManyToMany(mappedBy = "modules", targetEntity = DistributionSet.class, fetch = FetchType.LAZY) + @ManyToMany(mappedBy = "modules", targetEntity = JpaDistributionSet.class, fetch = FetchType.LAZY) private final List assignedTo = new ArrayList<>(); @Column(name = "deleted") - private boolean deleted = false; + private boolean deleted; @Column(name = "vendor", nullable = true, length = 256) private String vendor; - @OneToMany(mappedBy = "softwareModule", cascade = { CascadeType.ALL }, targetEntity = LocalArtifact.class) + @OneToMany(mappedBy = "softwareModule", cascade = { CascadeType.ALL }, targetEntity = JpaLocalArtifact.class) private List artifacts; - @OneToMany(mappedBy = "softwareModule", cascade = { CascadeType.ALL }, targetEntity = ExternalArtifact.class) + @OneToMany(mappedBy = "softwareModule", cascade = { CascadeType.ALL }, targetEntity = JpaExternalArtifact.class) private List externalArtifacts; @CascadeOnDelete - @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE }) + @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE }, targetEntity = JpaSoftwareModuleMetadata.class) @JoinColumn(name = "sw_id", insertable = false, updatable = false) private final List metadata = new ArrayList<>(); /** * Default constructor. */ - public SoftwareModule() { + public JpaSoftwareModule() { super(); } @@ -91,17 +101,18 @@ public class SoftwareModule extends NamedVersionedEntity { * @param vendor * of the {@link SoftwareModule} */ - public SoftwareModule(final SoftwareModuleType type, final String name, final String version, + public JpaSoftwareModule(final SoftwareModuleType type, final String name, final String version, final String description, final String vendor) { super(name, version, description); this.vendor = vendor; - this.type = type; + this.type = (JpaSoftwareModuleType) type; } /** * @param artifact * is added to the assigned {@link Artifact}s. */ + @Override public void addArtifact(final LocalArtifact artifact) { if (null == artifacts) { artifacts = new ArrayList<>(4); @@ -116,6 +127,7 @@ public class SoftwareModule extends NamedVersionedEntity { * @param artifact * is added to the assigned {@link Artifact}s. */ + @Override public void addArtifact(final ExternalArtifact artifact) { if (null == externalArtifacts) { externalArtifacts = new ArrayList<>(4); @@ -132,6 +144,7 @@ public class SoftwareModule extends NamedVersionedEntity { * to look for * @return found {@link Artifact} */ + @Override public Optional getLocalArtifact(final Long artifactId) { if (null == artifacts) { return Optional.empty(); @@ -145,6 +158,7 @@ public class SoftwareModule extends NamedVersionedEntity { * to look for * @return found {@link Artifact} */ + @Override public Optional getLocalArtifactByFilename(final String fileName) { if (null == artifacts) { return Optional.empty(); @@ -157,6 +171,7 @@ public class SoftwareModule extends NamedVersionedEntity { /** * @return the artifacts */ + @Override public List getArtifacts() { final List result = new ArrayList<>(); result.addAll(artifacts); @@ -168,6 +183,7 @@ public class SoftwareModule extends NamedVersionedEntity { /** * @return local artifacts only */ + @Override public List getLocalArtifacts() { if (artifacts == null) { return Collections.emptyList(); @@ -176,6 +192,7 @@ public class SoftwareModule extends NamedVersionedEntity { return artifacts; } + @Override public String getVendor() { return vendor; } @@ -184,6 +201,7 @@ public class SoftwareModule extends NamedVersionedEntity { * @param artifact * is removed from the assigned {@link LocalArtifact}s. */ + @Override public void removeArtifact(final LocalArtifact artifact) { if (null != artifacts) { artifacts.remove(artifact); @@ -194,35 +212,42 @@ public class SoftwareModule extends NamedVersionedEntity { * @param artifact * is removed from the assigned {@link ExternalArtifact}s. */ + @Override public void removeArtifact(final ExternalArtifact artifact) { if (null != externalArtifacts) { externalArtifacts.remove(artifact); } } + @Override public void setVendor(final String vendor) { this.vendor = vendor; } + @Override public SoftwareModuleType getType() { return type; } + @Override public boolean isDeleted() { return deleted; } + @Override public void setDeleted(final boolean deleted) { this.deleted = deleted; } + @Override public void setType(final SoftwareModuleType type) { - this.type = type; + this.type = (JpaSoftwareModuleType) type; } /** * @return immutable list of meta data elements. */ + @Override public List getMetadata() { return Collections.unmodifiableList(metadata); } @@ -236,6 +261,7 @@ public class SoftwareModule extends NamedVersionedEntity { /** * @return the assignedTo */ + @Override public List getAssignedTo() { return assignedTo; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleMetadata.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaSoftwareModuleMetadata.java similarity index 74% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleMetadata.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaSoftwareModuleMetadata.java index 5ddd273d3..e8972eb97 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleMetadata.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaSoftwareModuleMetadata.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.ConstraintMode; import javax.persistence.Entity; @@ -18,6 +18,9 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; + /** * Metadata for {@link SoftwareModule}. * @@ -25,19 +28,19 @@ import javax.persistence.Table; @IdClass(SwMetadataCompositeKey.class) @Entity @Table(name = "sp_sw_metadata") -public class SoftwareModuleMetadata extends MetaData { +public class JpaSoftwareModuleMetadata extends AbstractJpaMetaData implements SoftwareModuleMetadata { private static final long serialVersionUID = 1L; @Id - @ManyToOne(targetEntity = SoftwareModule.class, fetch = FetchType.LAZY) + @ManyToOne(targetEntity = JpaSoftwareModule.class, fetch = FetchType.LAZY) @JoinColumn(name = "sw_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_metadata_sw")) private SoftwareModule softwareModule; - public SoftwareModuleMetadata() { + public JpaSoftwareModuleMetadata() { // default public constructor for JPA } - public SoftwareModuleMetadata(final String key, final SoftwareModule softwareModule, final String value) { + public JpaSoftwareModuleMetadata(final String key, final SoftwareModule softwareModule, final String value) { super(key, value); this.softwareModule = softwareModule; } @@ -46,10 +49,12 @@ public class SoftwareModuleMetadata extends MetaData { return new SwMetadataCompositeKey(softwareModule, getKey()); } + @Override public SoftwareModule getSoftwareModule() { return softwareModule; } + @Override public void setSoftwareModule(final SoftwareModule softwareModule) { this.softwareModule = softwareModule; } @@ -63,11 +68,13 @@ public class SoftwareModuleMetadata extends MetaData { } @Override + // exception squid:S2259 - obj is checked for null in super + @SuppressWarnings("squid:S2259") public boolean equals(final Object obj) { if (!super.equals(obj)) { return false; } - final SoftwareModuleMetadata other = (SoftwareModuleMetadata) obj; + final JpaSoftwareModuleMetadata other = (JpaSoftwareModuleMetadata) obj; if (softwareModule == null) { if (other.softwareModule != null) { return false; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleType.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaSoftwareModuleType.java similarity index 72% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleType.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaSoftwareModuleType.java index f31b74ff6..f2a716c40 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleType.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaSoftwareModuleType.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Column; import javax.persistence.Entity; @@ -14,6 +14,8 @@ import javax.persistence.Index; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; + /** * Type of a software modules. * @@ -24,7 +26,10 @@ import javax.persistence.UniqueConstraint; @Index(name = "sp_idx_software_module_type_prim", columnList = "tenant,id") }, uniqueConstraints = { @UniqueConstraint(columnNames = { "type_key", "tenant" }, name = "uk_smt_type_key"), @UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_smt_name") }) -public class SoftwareModuleType extends NamedEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaSoftwareModuleType extends AbstractJpaNamedEntity implements SoftwareModuleType { private static final long serialVersionUID = 1L; @Column(name = "type_key", nullable = false, length = 64) @@ -37,7 +42,7 @@ public class SoftwareModuleType extends NamedEntity { private String colour; @Column(name = "deleted") - private boolean deleted = false; + private boolean deleted; /** * Constructor. @@ -51,7 +56,8 @@ public class SoftwareModuleType extends NamedEntity { * @param maxAssignments * assignments to a DS */ - public SoftwareModuleType(final String key, final String name, final String description, final int maxAssignments) { + public JpaSoftwareModuleType(final String key, final String name, final String description, + final int maxAssignments) { this(key, name, description, maxAssignments, null); } @@ -69,8 +75,8 @@ public class SoftwareModuleType extends NamedEntity { * @param colour * of the type. It will be null by default */ - public SoftwareModuleType(final String key, final String name, final String description, final int maxAssignments, - final String colour) { + public JpaSoftwareModuleType(final String key, final String name, final String description, + final int maxAssignments, final String colour) { super(); this.key = key; this.maxAssignments = maxAssignments; @@ -80,20 +86,28 @@ public class SoftwareModuleType extends NamedEntity { } /** - * Default Constructor. + * Default Constructor for JPA. */ - public SoftwareModuleType() { - super(); + public JpaSoftwareModuleType() { + // Default Constructor for JPA. } + @Override + public void setMaxAssignments(final int maxAssignments) { + this.maxAssignments = maxAssignments; + } + + @Override public String getKey() { return key; } + @Override public int getMaxAssignments() { return maxAssignments; } + @Override public boolean isDeleted() { return deleted; } @@ -102,10 +116,12 @@ public class SoftwareModuleType extends NamedEntity { this.deleted = deleted; } + @Override public String getColour() { return colour; } + @Override public void setColour(final String colour) { this.colour = colour; } @@ -114,4 +130,9 @@ public class SoftwareModuleType extends NamedEntity { public String toString() { return "SoftwareModuleType [key=" + key + ", getName()=" + getName() + ", getId()=" + getId() + "]"; } + + @Override + public void setKey(final String key) { + this.key = key; + } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Target.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java similarity index 76% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Target.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java index 8947ea6c3..183405470 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Target.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.util.ArrayList; import java.util.HashSet; @@ -36,26 +36,19 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.repository.model.helper.SecurityChecker; -import org.eclipse.hawkbit.repository.model.helper.SecurityTokenGeneratorHolder; -import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityChecker; +import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.persistence.annotations.CascadeOnDelete; import org.springframework.data.domain.Persistable; /** - *

- * The {@link Target} is the target of all provisioning operations. It contains - * the currently installed {@link DistributionSet} (i.e. current state). In - * addition it holds the target {@link DistributionSet} that has to be - * provisioned next (i.e. target state). - *

- * - *

- * {@link #getStatus()}s() shows if the {@link Target} is - * {@link TargetStatus#IN_SYNC} or a provisioning is - * {@link TargetStatus#PENDING} or the target is only - * {@link TargetStatus#REGISTERED}, i.e. a target {@link DistributionSet} . - *

+ * JPA implementation of {@link Target}. * */ @Entity @@ -68,7 +61,10 @@ import org.springframework.data.domain.Persistable; "controller_id", "tenant" }, name = "uk_tenant_controller_id")) @NamedEntityGraph(name = "Target.detail", attributeNodes = { @NamedAttributeNode("tags"), @NamedAttributeNode(value = "assignedDistributionSet"), @NamedAttributeNode(value = "targetInfo") }) -public class Target extends NamedEntity implements Persistable { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaTarget extends AbstractJpaNamedEntity implements Persistable, Target { private static final long serialVersionUID = 1L; @Column(name = "controller_id", length = 64) @@ -77,34 +73,35 @@ public class Target extends NamedEntity implements Persistable { private String controllerId; @Transient - private boolean entityNew = false; + private boolean entityNew; - @ManyToMany(targetEntity = TargetTag.class) + @ManyToMany(targetEntity = JpaTargetTag.class) @JoinTable(name = "sp_target_target_tag", joinColumns = { @JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_target")) }, inverseJoinColumns = { @JoinColumn(name = "tag", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_tag")) }) private Set tags = new HashSet<>(); @CascadeOnDelete - @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = { CascadeType.REMOVE }) + @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = { + CascadeType.REMOVE }, targetEntity = JpaAction.class) @JoinColumn(name = "target", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_act_hist_targ")) private final List actions = new ArrayList<>(); - @ManyToOne(optional = true, fetch = FetchType.LAZY, targetEntity = DistributionSet.class) + @ManyToOne(optional = true, fetch = FetchType.LAZY, targetEntity = JpaDistributionSet.class) @JoinColumn(name = "assigned_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_assign_ds")) - private DistributionSet assignedDistributionSet; + private JpaDistributionSet assignedDistributionSet; @CascadeOnDelete - @OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, targetEntity = TargetInfo.class) + @OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, targetEntity = JpaTargetInfo.class) @PrimaryKeyJoinColumn - private TargetInfo targetInfo = null; + private JpaTargetInfo targetInfo; /** * the security token of the target which allows if enabled to authenticate * with this security token. */ @Column(name = "sec_token", insertable = true, updatable = true, nullable = false, length = 128) - private String securityToken = null; + private String securityToken; @CascadeOnDelete @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE, CascadeType.PERSIST }) @@ -117,35 +114,50 @@ public class Target extends NamedEntity implements Persistable { * @param controllerId * controller ID of the {@link Target} */ - public Target(final String controllerId) { + public JpaTarget(final String controllerId) { + this(controllerId, SecurityTokenGeneratorHolder.getInstance().generateToken()); + } + + /** + * Constructor. + * + * @param controllerId + * controller ID of the {@link Target} + * @param securityToken + * for target authentication if enabled + */ + public JpaTarget(final String controllerId, final String securityToken) { this.controllerId = controllerId; setName(controllerId); - securityToken = SecurityTokenGeneratorHolder.getInstance().generateToken(); - targetInfo = new TargetInfo(this); + this.securityToken = securityToken; + targetInfo = new JpaTargetInfo(this); } /** * empty constructor for JPA. */ - Target() { + JpaTarget() { controllerId = null; securityToken = null; } + @Override public DistributionSet getAssignedDistributionSet() { return assignedDistributionSet; } + @Override public String getControllerId() { return controllerId; } + @Override public Set getTags() { return tags; } public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) { - this.assignedDistributionSet = assignedDistributionSet; + this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet; } public void setControllerId(final String controllerId) { @@ -156,14 +168,11 @@ public class Target extends NamedEntity implements Persistable { this.tags = tags; } + @Override public List getActions() { return actions; } - public TargetIdName getTargetIdName() { - return new TargetIdName(getId(), getControllerId(), getName()); - } - @Override @Transient public boolean isNew() { @@ -181,6 +190,7 @@ public class Target extends NamedEntity implements Persistable { /** * @return the targetInfo */ + @Override public TargetInfo getTargetInfo() { return targetInfo; } @@ -190,7 +200,7 @@ public class Target extends NamedEntity implements Persistable { * the targetInfo to set */ public void setTargetInfo(final TargetInfo targetInfo) { - this.targetInfo = targetInfo; + this.targetInfo = (JpaTargetInfo) targetInfo; } /** @@ -199,6 +209,7 @@ public class Target extends NamedEntity implements Persistable { * or the current context is executed as system code, otherwise * {@code null}. */ + @Override public String getSecurityToken() { if (SystemSecurityContextHolder.getInstance().getSystemSecurityContext().isCurrentThreadSystemCode() || SecurityChecker.hasPermission(SpPermission.READ_TARGET_SEC_TOKEN)) { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetFilterQuery.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetFilterQuery.java similarity index 66% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetFilterQuery.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetFilterQuery.java index 021b9ca7f..38275c71a 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetFilterQuery.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetFilterQuery.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Column; import javax.persistence.Entity; @@ -14,6 +14,8 @@ import javax.persistence.Index; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import org.eclipse.hawkbit.repository.model.TargetFilterQuery; + /** * Stored target filter. * @@ -22,7 +24,10 @@ import javax.persistence.UniqueConstraint; @Table(name = "sp_target_filter_query", indexes = { @Index(name = "sp_idx_target_filter_query_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_tenant_custom_filter_name")) -public class TargetFilterQuery extends TenantAwareBaseEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity implements TargetFilterQuery { private static final long serialVersionUID = 7493966984413479089L; @Column(name = "name", length = 64) @@ -31,27 +36,39 @@ public class TargetFilterQuery extends TenantAwareBaseEntity { @Column(name = "query", length = 1024) private String query; - public TargetFilterQuery() { + public JpaTargetFilterQuery() { // Default constructor for JPA. } - public TargetFilterQuery(final String name, final String query) { + /** + * Public constructor. + * + * @param name + * of the {@link TargetFilterQuery}. + * @param query + * of the {@link TargetFilterQuery}. + */ + public JpaTargetFilterQuery(final String name, final String query) { this.name = name; this.query = query; } + @Override public String getName() { return name; } + @Override public void setName(final String name) { this.name = name; } + @Override public String getQuery() { return query; } + @Override public void setQuery(final String query) { this.query = query; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetInfo.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java similarity index 76% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetInfo.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java index 00a501540..0606def4f 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetInfo.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java @@ -6,9 +6,8 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; -import java.io.Serializable; import java.net.URI; import java.time.Duration; import java.time.Instant; @@ -38,8 +37,14 @@ import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Transient; -import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder; -import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder; +import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException; +import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.PollStatus; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.eclipse.persistence.annotations.CascadeOnDelete; @@ -59,7 +64,7 @@ import org.springframework.data.domain.Persistable; @Table(name = "sp_target_info", indexes = { @Index(name = "sp_idx_target_info_02", columnList = "target_id,update_status") }) @Entity -public class TargetInfo implements Persistable, Serializable { +public class JpaTargetInfo implements Persistable, TargetInfo { private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(TargetInfo.class); @@ -68,19 +73,20 @@ public class TargetInfo implements Persistable, Serializable { private Long targetId; @Transient - private boolean entityNew = false; + private boolean entityNew; @CascadeOnDelete - @OneToOne(cascade = { CascadeType.MERGE, CascadeType.REMOVE }, fetch = FetchType.LAZY, targetEntity = Target.class) + @OneToOne(cascade = { CascadeType.MERGE, + CascadeType.REMOVE }, fetch = FetchType.LAZY, targetEntity = JpaTarget.class) @JoinColumn(name = "target_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_stat_targ")) @MapsId - private Target target; + private JpaTarget target; @Column(name = "address", length = 512) - private String address = null; + private String address; @Column(name = "last_target_query") - private Long lastTargetQuery = null; + private Long lastTargetQuery; @Column(name = "install_date") private Long installationDate; @@ -91,7 +97,7 @@ public class TargetInfo implements Persistable, Serializable { @ManyToOne(optional = true, fetch = FetchType.LAZY) @JoinColumn(name = "installed_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_inst_ds")) - private DistributionSet installedDistributionSet; + private JpaDistributionSet installedDistributionSet; /** * Read only on management API. Are commited by controller. @@ -116,12 +122,12 @@ public class TargetInfo implements Persistable, Serializable { * @param target * related to this status. */ - public TargetInfo(final Target target) { + public JpaTargetInfo(final JpaTarget target) { this.target = target; targetId = target.getId(); } - TargetInfo() { + JpaTargetInfo() { target = null; targetId = null; } @@ -148,6 +154,7 @@ public class TargetInfo implements Persistable, Serializable { /** * @return the ipAddress */ + @Override public URI getAddress() { if (address == null) { return null; @@ -162,15 +169,21 @@ public class TargetInfo implements Persistable, Serializable { /** * @param address - * the ipAddress to set + * the target address to set * * @throws IllegalArgumentException * If the given string violates RFC 2396 */ + @Override public void setAddress(final String address) { // check if this is a real URI if (address != null) { - URI.create(address); + try { + URI.create(address); + } catch (final IllegalArgumentException e) { + throw new InvalidTargetAddressException( + "The given address " + address + " violates the RFC-2396 specification", e); + } } this.address = address; @@ -184,14 +197,16 @@ public class TargetInfo implements Persistable, Serializable { this.targetId = targetId; } + @Override public Target getTarget() { return target; } - public void setTarget(final Target target) { + public void setTarget(final JpaTarget target) { this.target = target; } + @Override public Long getLastTargetQuery() { return lastTargetQuery; } @@ -204,14 +219,17 @@ public class TargetInfo implements Persistable, Serializable { this.requestControllerAttributes = requestControllerAttributes; } + @Override public Map getControllerAttributes() { return controllerAttributes; } + @Override public boolean isRequestControllerAttributes() { return requestControllerAttributes; } + @Override public Long getInstallationDate() { return installationDate; } @@ -220,6 +238,7 @@ public class TargetInfo implements Persistable, Serializable { this.installationDate = installationDate; } + @Override public TargetUpdateStatus getUpdateStatus() { return updateStatus; } @@ -228,11 +247,12 @@ public class TargetInfo implements Persistable, Serializable { this.updateStatus = updateStatus; } + @Override public DistributionSet getInstalledDistributionSet() { return installedDistributionSet; } - public void setInstalledDistributionSet(final DistributionSet installedDistributionSet) { + public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) { this.installedDistributionSet = installedDistributionSet; } @@ -242,6 +262,7 @@ public class TargetInfo implements Persistable, Serializable { * {@link #lastTargetQuery} is not set e.g. the target never polled * before this method returns {@code null} */ + @Override public PollStatus getPollStatus() { if (lastTargetQuery == null) { return null; @@ -263,63 +284,6 @@ public class TargetInfo implements Persistable, Serializable { }); } - /** - * The poll time object which holds all the necessary information around the - * target poll time, e.g. the last poll time, the next poll time and the - * overdue poll time. - * - */ - public static final class PollStatus { - private final LocalDateTime lastPollDate; - private final LocalDateTime nextPollDate; - private final LocalDateTime overdueDate; - private final LocalDateTime currentDate; - - private PollStatus(final LocalDateTime lastPollDate, final LocalDateTime nextPollDate, - final LocalDateTime overdueDate, final LocalDateTime currentDate) { - this.lastPollDate = lastPollDate; - this.nextPollDate = nextPollDate; - this.overdueDate = overdueDate; - this.currentDate = currentDate; - } - - /** - * calculates if the target poll time is overdue and the target has not - * been polled in the configured poll time interval. - * - * @return {@code true} if the current time is after the poll time - * overdue date otherwise {@code false}. - */ - public boolean isOverdue() { - return currentDate.isAfter(overdueDate); - } - - /** - * @return the lastPollDate - */ - public LocalDateTime getLastPollDate() { - return lastPollDate; - } - - public LocalDateTime getNextPollDate() { - return nextPollDate; - } - - public LocalDateTime getOverdueDate() { - return overdueDate; - } - - public LocalDateTime getCurrentDate() { - return currentDate; - } - - @Override - public String toString() { - return "PollTime [lastPollDate=" + lastPollDate + ", nextPollDate=" + nextPollDate + ", overdueDate=" - + overdueDate + ", currentDate=" + currentDate + "]"; - } - } - @Override public int hashCode() { final int prime = 31; @@ -340,7 +304,7 @@ public class TargetInfo implements Persistable, Serializable { if (!(obj instanceof TargetInfo)) { return false; } - final TargetInfo other = (TargetInfo) obj; + final JpaTargetInfo other = (JpaTargetInfo) obj; if (target == null) { if (other.target != null) { return false; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetTag.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetTag.java similarity index 78% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetTag.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetTag.java index 5a5a310d0..96989f14a 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetTag.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetTag.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.util.List; @@ -17,6 +17,9 @@ import javax.persistence.ManyToMany; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetTag; + /** * A {@link TargetTag} is used to describe Target attributes and use them also * for filtering the target list. @@ -26,10 +29,10 @@ import javax.persistence.UniqueConstraint; @Table(name = "sp_target_tag", indexes = { @Index(name = "sp_idx_target_tag_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_targ_tag")) -public class TargetTag extends Tag { +public class JpaTargetTag extends AbstractJpaTag implements TargetTag { private static final long serialVersionUID = 1L; - @ManyToMany(mappedBy = "tags", targetEntity = Target.class, fetch = FetchType.LAZY) + @ManyToMany(mappedBy = "tags", targetEntity = JpaTarget.class, fetch = FetchType.LAZY) private List assignedToTargets; /** @@ -42,7 +45,7 @@ public class TargetTag extends Tag { * @param colour * of {@link TargetTag} */ - public TargetTag(final String name, final String description, final String colour) { + public JpaTargetTag(final String name, final String description, final String colour) { super(name, description, colour); } @@ -52,14 +55,15 @@ public class TargetTag extends Tag { * @param name * of the {@link TargetTag} **/ - public TargetTag(final String name) { + public JpaTargetTag(final String name) { super(name, null, null); } - TargetTag() { - super(); + public JpaTargetTag() { + // Default constructor for JPA. } + @Override public List getAssignedToTargets() { return assignedToTargets; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTenantConfiguration.java similarity index 74% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfiguration.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTenantConfiguration.java index 5a938563b..d6f9a7a97 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTenantConfiguration.java @@ -6,9 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; - -import java.io.Serializable; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Basic; import javax.persistence.Column; @@ -16,6 +14,8 @@ import javax.persistence.Entity; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import org.eclipse.hawkbit.repository.model.TenantConfiguration; + /** * A JPA entity which stores the tenant specific configuration. * @@ -23,7 +23,10 @@ import javax.persistence.UniqueConstraint; @Entity @Table(name = "sp_tenant_configuration", uniqueConstraints = @UniqueConstraint(columnNames = { "conf_key", "tenant" }, name = "uk_tenant_key")) -public class TenantConfiguration extends TenantAwareBaseEntity implements Serializable { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaTenantConfiguration extends AbstractJpaTenantAwareBaseEntity implements TenantConfiguration { private static final long serialVersionUID = 1L; @Column(name = "conf_key", length = 128) @@ -36,7 +39,7 @@ public class TenantConfiguration extends TenantAwareBaseEntity implements Serial /** * JPA default constructor. */ - public TenantConfiguration() { + public JpaTenantConfiguration() { // JPA default constructor. } @@ -46,24 +49,28 @@ public class TenantConfiguration extends TenantAwareBaseEntity implements Serial * @param value * the value of this configuration */ - public TenantConfiguration(final String key, final String value) { + public JpaTenantConfiguration(final String key, final String value) { this.key = key; this.value = value; } + @Override public String getKey() { return key; } + @Override public void setKey(final String key) { this.key = key; } + @Override public String getValue() { return value; } + @Override public void setValue(final String value) { this.value = value; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantMetaData.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTenantMetaData.java similarity index 74% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantMetaData.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTenantMetaData.java index a9572c21c..9363a4db8 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TenantMetaData.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTenantMetaData.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import javax.persistence.Column; import javax.persistence.ConstraintMode; @@ -20,6 +20,10 @@ import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; +import org.eclipse.hawkbit.repository.model.TenantMetaData; + /** * Tenant entity with meta data that is configured globally for the entire * tenant. This entity is not tenant aware to allow the system to access it @@ -32,7 +36,10 @@ import javax.persistence.UniqueConstraint; @Index(name = "sp_idx_tenant_prim", columnList = "tenant,id") }, uniqueConstraints = { @UniqueConstraint(columnNames = { "tenant" }, name = "uk_tenantmd_tenant") }) @Entity -public class TenantMetaData extends BaseEntity { +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaTenantMetaData extends AbstractJpaBaseEntity implements TenantMetaData { private static final long serialVersionUID = 1L; @Column(name = "tenant", nullable = false, length = 40) @@ -40,12 +47,12 @@ public class TenantMetaData extends BaseEntity { @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "default_ds_type", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_tenant_md_default_ds_type")) - private DistributionSetType defaultDsType; + private JpaDistributionSetType defaultDsType; /** * Default constructor needed for JPA entities. */ - public TenantMetaData() { + public JpaTenantMetaData() { // Default constructor needed for JPA entities. } @@ -56,20 +63,23 @@ public class TenantMetaData extends BaseEntity { * of this tenant * @param tenant */ - public TenantMetaData(final DistributionSetType defaultDsType, final String tenant) { + public JpaTenantMetaData(final DistributionSetType defaultDsType, final String tenant) { super(); - this.defaultDsType = defaultDsType; + this.defaultDsType = (JpaDistributionSetType) defaultDsType; this.tenant = tenant; } + @Override public DistributionSetType getDefaultDsType() { return defaultDsType; } + @Override public void setDefaultDsType(final DistributionSetType defaultDsType) { - this.defaultDsType = defaultDsType; + this.defaultDsType = (JpaDistributionSetType) defaultDsType; } + @Override public String getTenant() { return tenant; } @@ -77,24 +87,4 @@ public class TenantMetaData extends BaseEntity { public void setTenant(final String tenant) { this.tenant = tenant; } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + this.getClass().getName().hashCode(); - return result; - } - - @Override - public boolean equals(final Object obj) { - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof TenantMetaData)) { - return false; - } - - return true; - } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutTargetGroup.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/RolloutTargetGroup.java similarity index 77% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutTargetGroup.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/RolloutTargetGroup.java index 7a46b15b1..0bb969c7f 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutTargetGroup.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/RolloutTargetGroup.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.io.Serializable; import java.util.List; @@ -24,6 +24,9 @@ import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.persistence.annotations.ExistenceChecking; import org.eclipse.persistence.annotations.ExistenceType; @@ -41,16 +44,16 @@ public class RolloutTargetGroup implements Serializable { private static final long serialVersionUID = 1L; @Id - @ManyToOne(targetEntity = RolloutGroup.class, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }) - @JoinColumn(name = "rolloutGroup_Id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollouttargetgroup_group") ) + @ManyToOne(targetEntity = JpaRolloutGroup.class, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }) + @JoinColumn(name = "rolloutGroup_Id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollouttargetgroup_group")) private RolloutGroup rolloutGroup; @Id - @ManyToOne(targetEntity = Target.class, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }) - @JoinColumn(name = "target_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollouttargetgroup_target") ) - private Target target; + @ManyToOne(targetEntity = JpaTarget.class, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }) + @JoinColumn(name = "target_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollouttargetgroup_target")) + private JpaTarget target; - @OneToMany(targetEntity = Action.class, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }) + @OneToMany(targetEntity = JpaAction.class, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }) @JoinColumns(value = { @JoinColumn(name = "rolloutgroup", referencedColumnName = "rolloutGroup_Id"), @JoinColumn(name = "target", referencedColumnName = "target_id") }) private List actions; @@ -64,7 +67,7 @@ public class RolloutTargetGroup implements Serializable { public RolloutTargetGroup(final RolloutGroup rolloutGroup, final Target target) { this.rolloutGroup = rolloutGroup; - this.target = target; + this.target = (JpaTarget) target; } public RolloutTargetGroupId getId() { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutTargetGroupId.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/RolloutTargetGroupId.java similarity index 88% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutTargetGroupId.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/RolloutTargetGroupId.java index 88226142a..b4001d9dc 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutTargetGroupId.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/RolloutTargetGroupId.java @@ -6,10 +6,13 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.io.Serializable; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.Target; + /** * Combined unique key of the table {@link RolloutTargetGroup}. * @@ -47,4 +50,4 @@ public class RolloutTargetGroupId implements Serializable { public Long getTarget() { return target; } -} \ No newline at end of file +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SwMetadataCompositeKey.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/SwMetadataCompositeKey.java similarity index 96% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SwMetadataCompositeKey.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/SwMetadataCompositeKey.java index 90b3779a1..e9c63b511 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SwMetadataCompositeKey.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/SwMetadataCompositeKey.java @@ -6,10 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import java.io.Serializable; +import org.eclipse.hawkbit.repository.model.SoftwareModule; + /** * The Software Module meta data composite key which contains the meta data key * and the ID of the software module itself. diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/AfterTransactionCommitExecutorHolder.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/AfterTransactionCommitExecutorHolder.java similarity index 87% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/AfterTransactionCommitExecutorHolder.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/AfterTransactionCommitExecutorHolder.java index 1282bc99d..a0e918585 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/AfterTransactionCommitExecutorHolder.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/AfterTransactionCommitExecutorHolder.java @@ -6,10 +6,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model.helper; +package org.eclipse.hawkbit.repository.jpa.model.helper; -import org.eclipse.hawkbit.eventbus.EntityPropertyChangeListener; -import org.eclipse.hawkbit.executor.AfterTransactionCommitExecutor; +import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; +import org.eclipse.hawkbit.repository.jpa.model.EntityPropertyChangeListener; import org.springframework.beans.factory.annotation.Autowired; /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/CacheManagerHolder.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/CacheManagerHolder.java similarity index 92% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/CacheManagerHolder.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/CacheManagerHolder.java index c8c081d95..64417c7d6 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/CacheManagerHolder.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/CacheManagerHolder.java @@ -6,9 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model.helper; +package org.eclipse.hawkbit.repository.jpa.model.helper; -import org.eclipse.hawkbit.eventbus.CacheFieldEntityListener; +import org.eclipse.hawkbit.repository.jpa.model.CacheFieldEntityListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.CacheManager; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SecurityChecker.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SecurityChecker.java similarity index 96% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SecurityChecker.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SecurityChecker.java index 7c9763e6d..da4f223e6 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SecurityChecker.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SecurityChecker.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model.helper; +package org.eclipse.hawkbit.repository.jpa.model.helper; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SecurityTokenGeneratorHolder.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SecurityTokenGeneratorHolder.java similarity index 96% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SecurityTokenGeneratorHolder.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SecurityTokenGeneratorHolder.java index ffc1e308f..64c158c87 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SecurityTokenGeneratorHolder.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SecurityTokenGeneratorHolder.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model.helper; +package org.eclipse.hawkbit.repository.jpa.model.helper; import org.eclipse.hawkbit.security.SecurityTokenGenerator; import org.springframework.beans.factory.annotation.Autowired; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SystemSecurityContextHolder.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SystemSecurityContextHolder.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SystemSecurityContextHolder.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SystemSecurityContextHolder.java index 7d005e9bc..109c11280 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SystemSecurityContextHolder.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/SystemSecurityContextHolder.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model.helper; +package org.eclipse.hawkbit.repository.jpa.model.helper; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.springframework.beans.factory.annotation.Autowired; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/TenantAwareHolder.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantAwareHolder.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/TenantAwareHolder.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantAwareHolder.java index 5b85745d7..a034cd605 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/TenantAwareHolder.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantAwareHolder.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model.helper; +package org.eclipse.hawkbit.repository.jpa.model.helper; import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.beans.factory.annotation.Autowired; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/TenantConfigurationManagementHolder.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantConfigurationManagementHolder.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/TenantConfigurationManagementHolder.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantConfigurationManagementHolder.java index 700511db6..239274c45 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/TenantConfigurationManagementHolder.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantConfigurationManagementHolder.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model.helper; +package org.eclipse.hawkbit.repository.jpa.model.helper; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.springframework.beans.factory.annotation.Autowired; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutScheduler.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/RolloutScheduler.java similarity index 87% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutScheduler.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/RolloutScheduler.java index 6671ad896..7335c1cb6 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutScheduler.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/RolloutScheduler.java @@ -6,10 +6,13 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa.rollout; import java.util.List; +import org.eclipse.hawkbit.repository.RolloutManagement; +import org.eclipse.hawkbit.repository.RolloutProperties; +import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; import org.slf4j.Logger; @@ -31,7 +34,7 @@ import org.springframework.stereotype.Component; @Profile("!test") public class RolloutScheduler { - private static final Logger logger = LoggerFactory.getLogger(RolloutScheduler.class); + private static final Logger LOGGER = LoggerFactory.getLogger(RolloutScheduler.class); @Autowired private TenantAware tenantAware; @@ -56,7 +59,7 @@ public class RolloutScheduler { */ @Scheduled(initialDelayString = RolloutProperties.Scheduler.PROP_SCHEDULER_DELAY_PLACEHOLDER, fixedDelayString = RolloutProperties.Scheduler.PROP_SCHEDULER_DELAY_PLACEHOLDER) public void rolloutScheduler() { - logger.debug("rollout schedule checker has been triggered."); + LOGGER.debug("rollout schedule checker has been triggered."); // run this code in system code privileged to have the necessary // permission to query and create entities. systemSecurityContext.runAsSystem(() -> { @@ -67,7 +70,7 @@ public class RolloutScheduler { // iterate through all tenants and execute the rollout check for // each tenant seperately. final List tenants = systemManagement.findTenants(); - logger.info("Checking rollouts for {} tenants", tenants.size()); + LOGGER.info("Checking rollouts for {} tenants", tenants.size()); for (final String tenant : tenants) { tenantAware.runAsTenant(tenant, () -> { rolloutManagement.checkRunningRollouts(rolloutProperties.getScheduler().getFixedDelay()); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/PauseRolloutGroupAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/PauseRolloutGroupAction.java similarity index 74% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/PauseRolloutGroupAction.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/PauseRolloutGroupAction.java index af335cd0d..e20f632f8 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/PauseRolloutGroupAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/PauseRolloutGroupAction.java @@ -6,12 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rollout.condition; +package org.eclipse.hawkbit.repository.jpa.rollout.condition; -import java.util.concurrent.Callable; - -import org.eclipse.hawkbit.repository.RolloutGroupRepository; import org.eclipse.hawkbit.repository.RolloutManagement; +import org.eclipse.hawkbit.repository.jpa.RolloutGroupRepository; +import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; @@ -42,14 +41,11 @@ public class PauseRolloutGroupAction implements RolloutGroupActionEvaluator { @Override public void eval(final Rollout rollout, final RolloutGroup rolloutGroup, final String expression) { - systemSecurityContext.runAsSystem(new Callable() { - @Override - public Void call() throws Exception { - rolloutGroup.setStatus(RolloutGroupStatus.ERROR); - rolloutGroupRepository.save(rolloutGroup); - rolloutManagement.pauseRollout(rollout); - return null; - } + systemSecurityContext.runAsSystem(() -> { + rolloutGroup.setStatus(RolloutGroupStatus.ERROR); + rolloutGroupRepository.save((JpaRolloutGroup) rolloutGroup); + rolloutManagement.pauseRollout(rollout); + return null; }); } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/RolloutGroupActionEvaluator.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/RolloutGroupActionEvaluator.java similarity index 91% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/RolloutGroupActionEvaluator.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/RolloutGroupActionEvaluator.java index 1e2c98707..d375e68c5 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/RolloutGroupActionEvaluator.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/RolloutGroupActionEvaluator.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rollout.condition; +package org.eclipse.hawkbit.repository.jpa.rollout.condition; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/RolloutGroupConditionEvaluator.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/RolloutGroupConditionEvaluator.java similarity index 87% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/RolloutGroupConditionEvaluator.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/RolloutGroupConditionEvaluator.java index 62c9050b1..0690f72ec 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/RolloutGroupConditionEvaluator.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/RolloutGroupConditionEvaluator.java @@ -6,14 +6,15 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rollout.condition; +package org.eclipse.hawkbit.repository.jpa.rollout.condition; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; /** - * + * Verifies {@link RolloutGroup#getErrorConditionExp()}. */ +@FunctionalInterface public interface RolloutGroupConditionEvaluator { default boolean verifyExpression(final String expression) { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/StartNextGroupRolloutGroupSuccessAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/StartNextGroupRolloutGroupSuccessAction.java similarity index 89% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/StartNextGroupRolloutGroupSuccessAction.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/StartNextGroupRolloutGroupSuccessAction.java index 21c499d31..e12a26bac 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/StartNextGroupRolloutGroupSuccessAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/StartNextGroupRolloutGroupSuccessAction.java @@ -6,12 +6,13 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rollout.condition; +package org.eclipse.hawkbit.repository.jpa.rollout.condition; import java.util.List; import org.eclipse.hawkbit.repository.DeploymentManagement; -import org.eclipse.hawkbit.repository.RolloutGroupRepository; +import org.eclipse.hawkbit.repository.jpa.RolloutGroupRepository; +import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; @@ -68,7 +69,7 @@ public class StartNextGroupRolloutGroupSuccessAction implements RolloutGroupActi final RolloutGroup nextGroup = action.getRolloutGroup(); logger.debug("Rolloutgroup {} is now running", nextGroup); nextGroup.setStatus(RolloutGroupStatus.RUNNING); - rolloutGroupRepository.save(nextGroup); + rolloutGroupRepository.save((JpaRolloutGroup) nextGroup); }); } else { logger.info("No actions to start for next rolloutgroup of parent {}", rolloutGroup); @@ -76,8 +77,8 @@ public class StartNextGroupRolloutGroupSuccessAction implements RolloutGroupActi // e.g. if targets has been deleted after the group has been // scheduled. If the group is empty now, we just finish the group if // there are not actions available for this group. - final List findByRolloutGroupParent = rolloutGroupRepository - .findByParentAndStatus(rolloutGroup, RolloutGroupStatus.SCHEDULED); + final List findByRolloutGroupParent = rolloutGroupRepository + .findByParentAndStatus((JpaRolloutGroup) rolloutGroup, RolloutGroupStatus.SCHEDULED); findByRolloutGroupParent.forEach(nextGroup -> { logger.debug("Rolloutgroup {} is finished, starting next group", nextGroup); nextGroup.setStatus(RolloutGroupStatus.FINISHED); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupErrorCondition.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/ThresholdRolloutGroupErrorCondition.java similarity index 85% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupErrorCondition.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/ThresholdRolloutGroupErrorCondition.java index 6e63efa8e..cba134402 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupErrorCondition.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/ThresholdRolloutGroupErrorCondition.java @@ -6,9 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rollout.condition; +package org.eclipse.hawkbit.repository.jpa.rollout.condition; -import org.eclipse.hawkbit.repository.ActionRepository; +import org.eclipse.hawkbit.repository.jpa.ActionRepository; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; +import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; @@ -30,7 +32,8 @@ public class ThresholdRolloutGroupErrorCondition implements RolloutGroupConditio @Override public boolean eval(final Rollout rollout, final RolloutGroup rolloutGroup, final String expression) { - final Long totalGroup = actionRepository.countByRolloutAndRolloutGroup(rollout, rolloutGroup); + final Long totalGroup = actionRepository.countByRolloutAndRolloutGroup((JpaRollout) rollout, + (JpaRolloutGroup) rolloutGroup); final Long error = actionRepository.countByRolloutIdAndRolloutGroupIdAndStatus(rollout.getId(), rolloutGroup.getId(), Action.Status.ERROR); try { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupSuccessCondition.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/ThresholdRolloutGroupSuccessCondition.java similarity index 94% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupSuccessCondition.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/ThresholdRolloutGroupSuccessCondition.java index fcf9762c6..3e098c701 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupSuccessCondition.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/ThresholdRolloutGroupSuccessCondition.java @@ -6,9 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rollout.condition; +package org.eclipse.hawkbit.repository.jpa.rollout.condition; -import org.eclipse.hawkbit.repository.ActionRepository; +import org.eclipse.hawkbit.repository.jpa.ActionRepository; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/PropertyMapper.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/PropertyMapper.java similarity index 96% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/PropertyMapper.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/PropertyMapper.java index ffa0e9212..db4417960 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/PropertyMapper.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/PropertyMapper.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import java.util.HashMap; import java.util.Map; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLUtility.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java similarity index 99% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLUtility.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java index 4edc46623..91e03342e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLUtility.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import java.util.ArrayList; import java.util.Arrays; @@ -26,6 +26,8 @@ import javax.persistence.criteria.Root; import org.eclipse.hawkbit.repository.FieldNameProvider; import org.eclipse.hawkbit.repository.FieldValueConverter; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.SimpleTypeConverter; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/ActionSpecifications.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/ActionSpecifications.java similarity index 55% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/ActionSpecifications.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/ActionSpecifications.java index 62e7167f1..54d529d6c 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/ActionSpecifications.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/ActionSpecifications.java @@ -6,20 +6,22 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.specifications; +package org.eclipse.hawkbit.repository.jpa.specifications; import javax.persistence.criteria.Join; import javax.persistence.criteria.ListJoin; import javax.persistence.criteria.SetJoin; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction_; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; +import org.eclipse.hawkbit.repository.jpa.model.JpaLocalArtifact; +import org.eclipse.hawkbit.repository.jpa.model.JpaLocalArtifact_; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_; import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.Action_; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSet_; import org.eclipse.hawkbit.repository.model.LocalArtifact; -import org.eclipse.hawkbit.repository.model.LocalArtifact_; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModule_; import org.eclipse.hawkbit.repository.model.Target; import org.springframework.data.jpa.domain.Specification; @@ -28,7 +30,7 @@ import org.springframework.data.jpa.domain.Specification; * Spring Data JPQL Specifications. * */ -public class ActionSpecifications { +public final class ActionSpecifications { private ActionSpecifications() { // utility class @@ -47,15 +49,16 @@ public class ActionSpecifications { * assigned * @return a specification to use with spring JPA */ - public static Specification hasTargetAssignedArtifact(final Target target, + public static Specification hasTargetAssignedArtifact(final Target target, final LocalArtifact localArtifact) { return (actionRoot, query, criteriaBuilder) -> { - final Join dsJoin = actionRoot.join(Action_.distributionSet); - final SetJoin modulesJoin = dsJoin.join(DistributionSet_.modules); - final ListJoin artifactsJoin = modulesJoin.join(SoftwareModule_.artifacts); + final Join dsJoin = actionRoot.join(JpaAction_.distributionSet); + final SetJoin modulesJoin = dsJoin.join(JpaDistributionSet_.modules); + final ListJoin artifactsJoin = modulesJoin + .join(JpaSoftwareModule_.artifacts); return criteriaBuilder.and( - criteriaBuilder.equal(artifactsJoin.get(LocalArtifact_.filename), localArtifact.getFilename()), - criteriaBuilder.equal(actionRoot.get(Action_.target), target)); + criteriaBuilder.equal(artifactsJoin.get(JpaLocalArtifact_.filename), localArtifact.getFilename()), + criteriaBuilder.equal(actionRoot.get(JpaAction_.target), target)); }; } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/DistributionSetSpecification.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetSpecification.java similarity index 58% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/DistributionSetSpecification.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetSpecification.java index b95f0b8e7..4ee849bcc 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/DistributionSetSpecification.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetSpecification.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.specifications; +package org.eclipse.hawkbit.repository.jpa.specifications; import java.util.Collection; @@ -18,15 +18,17 @@ import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.SetJoin; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag_; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetTag; -import org.eclipse.hawkbit.repository.model.DistributionSetTag_; import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.DistributionSet_; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.hawkbit.repository.model.TargetInfo_; -import org.eclipse.hawkbit.repository.model.Target_; import org.springframework.data.jpa.domain.Specification; /** @@ -48,8 +50,8 @@ public final class DistributionSetSpecification { * attribute is ignored * @return the {@link DistributionSet} {@link Specification} */ - public static Specification isDeleted(final Boolean isDeleted) { - return (targetRoot, query, cb) -> cb.equal(targetRoot. get(DistributionSet_.deleted), isDeleted); + public static Specification isDeleted(final Boolean isDeleted) { + return (targetRoot, query, cb) -> cb.equal(targetRoot. get(JpaDistributionSet_.deleted), isDeleted); } @@ -62,8 +64,8 @@ public final class DistributionSetSpecification { * the attribute is ignored * @return the {@link DistributionSet} {@link Specification} */ - public static Specification isCompleted(final Boolean isCompleted) { - return (targetRoot, query, cb) -> cb.equal(targetRoot. get(DistributionSet_.complete), isCompleted); + public static Specification isCompleted(final Boolean isCompleted) { + return (targetRoot, query, cb) -> cb.equal(targetRoot. get(JpaDistributionSet_.complete), isCompleted); } @@ -75,12 +77,12 @@ public final class DistributionSetSpecification { * to search * @return the {@link DistributionSet} {@link Specification} */ - public static Specification byId(final Long distid) { + public static Specification byId(final Long distid) { return (targetRoot, query, cb) -> { - final Predicate predicate = cb.equal(targetRoot. get(DistributionSet_.id), distid); - targetRoot.fetch(DistributionSet_.modules, JoinType.LEFT); - targetRoot.fetch(DistributionSet_.tags, JoinType.LEFT); - targetRoot.fetch(DistributionSet_.type, JoinType.LEFT); + final Predicate predicate = cb.equal(targetRoot. get(JpaDistributionSet_.id), distid); + targetRoot.fetch(JpaDistributionSet_.modules, JoinType.LEFT); + targetRoot.fetch(JpaDistributionSet_.tags, JoinType.LEFT); + targetRoot.fetch(JpaDistributionSet_.type, JoinType.LEFT); query.distinct(true); return predicate; @@ -95,12 +97,12 @@ public final class DistributionSetSpecification { * to search * @return the {@link DistributionSet} {@link Specification} */ - public static Specification byIds(final Collection distids) { + public static Specification byIds(final Collection distids) { return (targetRoot, query, cb) -> { - final Predicate predicate = targetRoot. get(DistributionSet_.id).in(distids); - targetRoot.fetch(DistributionSet_.modules, JoinType.LEFT); - targetRoot.fetch(DistributionSet_.tags, JoinType.LEFT); - targetRoot.fetch(DistributionSet_.type, JoinType.LEFT); + final Predicate predicate = targetRoot. get(JpaDistributionSet_.id).in(distids); + targetRoot.fetch(JpaDistributionSet_.modules, JoinType.LEFT); + targetRoot.fetch(JpaDistributionSet_.tags, JoinType.LEFT); + targetRoot.fetch(JpaDistributionSet_.type, JoinType.LEFT); query.distinct(true); return predicate; }; @@ -114,11 +116,11 @@ public final class DistributionSetSpecification { * to be filtered on * @return the {@link DistributionSet} {@link Specification} */ - public static Specification likeNameOrDescriptionOrVersion(final String subString) { + public static Specification likeNameOrDescriptionOrVersion(final String subString) { return (targetRoot, query, cb) -> cb.or( - cb.like(cb.lower(targetRoot. get(DistributionSet_.name)), subString.toLowerCase()), - cb.like(cb.lower(targetRoot. get(DistributionSet_.version)), subString.toLowerCase()), - cb.like(cb.lower(targetRoot. get(DistributionSet_.description)), subString.toLowerCase())); + cb.like(cb.lower(targetRoot. get(JpaDistributionSet_.name)), subString.toLowerCase()), + cb.like(cb.lower(targetRoot. get(JpaDistributionSet_.version)), subString.toLowerCase()), + cb.like(cb.lower(targetRoot. get(JpaDistributionSet_.description)), subString.toLowerCase())); } /** @@ -131,10 +133,10 @@ public final class DistributionSetSpecification { * flag to select distribution sets with no tag * @return the {@link DistributionSet} {@link Specification} */ - public static Specification hasTags(final Collection tagNames, + public static Specification hasTags(final Collection tagNames, final Boolean selectDSWithNoTag) { return (targetRoot, query, cb) -> { - final SetJoin tags = targetRoot.join(DistributionSet_.tags, + final SetJoin tags = targetRoot.join(JpaDistributionSet_.tags, JoinType.LEFT); final Predicate predicate = getPredicate(tags, tagNames, selectDSWithNoTag, cb); query.distinct(true); @@ -142,10 +144,10 @@ public final class DistributionSetSpecification { }; } - private static Predicate getPredicate(final SetJoin tags, + private static Predicate getPredicate(final SetJoin tags, final Collection tagNames, final Boolean selectDSWithNoTag, final CriteriaBuilder cb) { - tags.get(DistributionSetTag_.name); - final Path exp = tags.get(DistributionSetTag_.name); + tags.get(JpaDistributionSetTag_.name); + final Path exp = tags.get(JpaDistributionSetTag_.name); if (selectDSWithNoTag != null && selectDSWithNoTag) { if (tagNames != null) { return cb.or(exp.isNull(), exp.in(tagNames)); @@ -167,11 +169,11 @@ public final class DistributionSetSpecification { * to be filtered on * @return the {@link Specification} */ - public static Specification equalsNameAndVersionIgnoreCase(final String name, + public static Specification equalsNameAndVersionIgnoreCase(final String name, final String version) { return (targetRoot, query, cb) -> cb.and( - cb.equal(cb.lower(targetRoot. get(DistributionSet_.name)), name.toLowerCase()), - cb.equal(cb.lower(targetRoot. get(DistributionSet_.version)), version.toLowerCase())); + cb.equal(cb.lower(targetRoot. get(JpaDistributionSet_.name)), name.toLowerCase()), + cb.equal(cb.lower(targetRoot. get(JpaDistributionSet_.version)), version.toLowerCase())); } @@ -183,8 +185,9 @@ public final class DistributionSetSpecification { * to search * @return the {@link DistributionSet} {@link Specification} */ - public static Specification byType(final DistributionSetType type) { - return (targetRoot, query, cb) -> cb.equal(targetRoot. get(DistributionSet_.type), type); + public static Specification byType(final DistributionSetType type) { + return (targetRoot, query, cb) -> cb.equal(targetRoot. get(JpaDistributionSet_.type), + type); } @@ -195,12 +198,12 @@ public final class DistributionSetSpecification { * @return the specification to search for a distribution set which is * installed to the given targetId */ - public static Specification installedTarget(final String installedTargetId) { + public static Specification installedTarget(final String installedTargetId) { return (dsRoot, query, cb) -> { - final ListJoin installedTargetJoin = dsRoot - .join(DistributionSet_.installedAtTargets, JoinType.INNER); - final Join targetJoin = installedTargetJoin.join(TargetInfo_.target); - return cb.equal(targetJoin.get(Target_.controllerId), installedTargetId); + final ListJoin installedTargetJoin = dsRoot + .join(JpaDistributionSet_.installedAtTargets, JoinType.INNER); + final Join targetJoin = installedTargetJoin.join(JpaTargetInfo_.target); + return cb.equal(targetJoin.get(JpaTarget_.controllerId), installedTargetId); }; } @@ -211,11 +214,11 @@ public final class DistributionSetSpecification { * @return the specification to search for a distribution set which is * assigned to the given targetId */ - public static Specification assignedTarget(final String assignedTargetId) { + public static Specification assignedTarget(final String assignedTargetId) { return (dsRoot, query, cb) -> { - final ListJoin assignedTargetJoin = dsRoot.join(DistributionSet_.assignedToTargets, - JoinType.INNER); - return cb.equal(assignedTargetJoin.get(Target_.controllerId), assignedTargetId); + final ListJoin assignedTargetJoin = dsRoot + .join(JpaDistributionSet_.assignedToTargets, JoinType.INNER); + return cb.equal(assignedTargetJoin.get(JpaTarget_.controllerId), assignedTargetId); }; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/DistributionSetTypeSpecification.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetTypeSpecification.java similarity index 75% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/DistributionSetTypeSpecification.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetTypeSpecification.java index 13776deb0..0a8306faa 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/DistributionSetTypeSpecification.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetTypeSpecification.java @@ -6,11 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.specifications; +package org.eclipse.hawkbit.repository.jpa.specifications; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType_; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.DistributionSetType_; import org.springframework.data.jpa.domain.Specification; /** @@ -31,8 +32,9 @@ public final class DistributionSetTypeSpecification { * attribute is ignored * @return the {@link DistributionSetType} {@link Specification} */ - public static Specification isDeleted(final Boolean isDeleted) { - return (targetRoot, query, cb) -> cb.equal(targetRoot. get(DistributionSetType_.deleted), isDeleted); + public static Specification isDeleted(final Boolean isDeleted) { + return (targetRoot, query, cb) -> cb.equal(targetRoot. get(JpaDistributionSetType_.deleted), + isDeleted); } /** @@ -44,8 +46,8 @@ public final class DistributionSetTypeSpecification { * to search * @return the {@link DistributionSet} {@link Specification} */ - public static Specification byId(final Long distid) { - return (targetRoot, query, cb) -> cb.equal(targetRoot. get(DistributionSetType_.id), distid); + public static Specification byId(final Long distid) { + return (targetRoot, query, cb) -> cb.equal(targetRoot. get(JpaDistributionSetType_.id), distid); } /** @@ -57,8 +59,8 @@ public final class DistributionSetTypeSpecification { * to search * @return the {@link DistributionSet} {@link Specification} */ - public static Specification byName(final String name) { - return (targetRoot, query, cb) -> cb.equal(targetRoot. get(DistributionSetType_.name), name); + public static Specification byName(final String name) { + return (targetRoot, query, cb) -> cb.equal(targetRoot. get(JpaDistributionSetType_.name), name); } /** @@ -70,8 +72,8 @@ public final class DistributionSetTypeSpecification { * to search * @return the {@link DistributionSet} {@link Specification} */ - public static Specification byKey(final String key) { - return (targetRoot, query, cb) -> cb.equal(targetRoot. get(DistributionSetType_.key), key); + public static Specification byKey(final String key) { + return (targetRoot, query, cb) -> cb.equal(targetRoot. get(JpaDistributionSetType_.key), key); } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/SoftwareModuleSpecification.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/SoftwareModuleSpecification.java similarity index 63% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/SoftwareModuleSpecification.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/SoftwareModuleSpecification.java index 680f97778..feba50ac8 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/SoftwareModuleSpecification.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/SoftwareModuleSpecification.java @@ -6,13 +6,14 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.specifications; +package org.eclipse.hawkbit.repository.jpa.specifications; import javax.persistence.criteria.Predicate; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.model.SoftwareModule_; import org.springframework.data.jpa.domain.Specification; /** @@ -33,10 +34,10 @@ public final class SoftwareModuleSpecification { * to search for * @return the {@link SoftwareModule} {@link Specification} */ - public static Specification byId(final Long moduleId) { + public static Specification byId(final Long moduleId) { return (targetRoot, query, cb) -> { - final Predicate predicate = cb.equal(targetRoot. get(SoftwareModule_.id), moduleId); - targetRoot.fetch(SoftwareModule_.type); + final Predicate predicate = cb.equal(targetRoot. get(JpaSoftwareModule_.id), moduleId); + targetRoot.fetch(JpaSoftwareModule_.type); return predicate; }; } @@ -47,8 +48,8 @@ public final class SoftwareModuleSpecification { * * @return the {@link SoftwareModule} {@link Specification} */ - public static Specification isDeletedFalse() { - return (swRoot, query, cb) -> cb.equal(swRoot. get(SoftwareModule_.deleted), Boolean.FALSE); + public static Specification isDeletedFalse() { + return (swRoot, query, cb) -> cb.equal(swRoot. get(JpaSoftwareModule_.deleted), Boolean.FALSE); } /** @@ -59,10 +60,10 @@ public final class SoftwareModuleSpecification { * to be filtered on * @return the {@link SoftwareModule} {@link Specification} */ - public static Specification likeNameOrVersion(final String subString) { + public static Specification likeNameOrVersion(final String subString) { return (targetRoot, query, cb) -> cb.or( - cb.like(cb.lower(targetRoot. get(SoftwareModule_.name)), subString.toLowerCase()), - cb.like(cb.lower(targetRoot. get(SoftwareModule_.version)), subString.toLowerCase())); + cb.like(cb.lower(targetRoot. get(JpaSoftwareModule_.name)), subString.toLowerCase()), + cb.like(cb.lower(targetRoot. get(JpaSoftwareModule_.version)), subString.toLowerCase())); } /** @@ -73,8 +74,9 @@ public final class SoftwareModuleSpecification { * to be filtered on * @return the {@link SoftwareModule} {@link Specification} */ - public static Specification equalType(final SoftwareModuleType type) { - return (targetRoot, query, cb) -> cb.equal(targetRoot. get(SoftwareModule_.type), type); + public static Specification equalType(final JpaSoftwareModuleType type) { + return (targetRoot, query, cb) -> cb.equal(targetRoot. get(JpaSoftwareModule_.type), + type); } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/SpecificationsBuilder.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/SpecificationsBuilder.java similarity index 95% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/SpecificationsBuilder.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/SpecificationsBuilder.java index 83a4c6f8b..005942719 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/SpecificationsBuilder.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/SpecificationsBuilder.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.specifications; +package org.eclipse.hawkbit.repository.jpa.specifications; import java.util.List; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/TargetFilterQuerySpecification.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetFilterQuerySpecification.java similarity index 51% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/TargetFilterQuerySpecification.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetFilterQuerySpecification.java index 0b600c849..4b27c7fc7 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/TargetFilterQuerySpecification.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetFilterQuerySpecification.java @@ -6,10 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.specifications; +package org.eclipse.hawkbit.repository.jpa.specifications; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery_; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; -import org.eclipse.hawkbit.repository.model.TargetFilterQuery_; import org.springframework.data.jpa.domain.Specification; /** @@ -17,15 +18,23 @@ import org.springframework.data.jpa.domain.Specification; * Spring Data JPQL Specifications. * */ -public class TargetFilterQuerySpecification { +public final class TargetFilterQuerySpecification { private TargetFilterQuerySpecification() { // utility class } - public static Specification likeName(final String searchText) { + /** + * {@link Specification} for retrieving {@link JpaTargetFilterQuery}s based + * on is {@link JpaTargetFilterQuery#getName()}. + * + * @param searchText + * of the filter + * @return the {@link JpaTargetFilterQuery} {@link Specification} + */ + public static Specification likeName(final String searchText) { return (targetFilterQueryRoot, query, cb) -> { final String searchTextToLower = searchText.toLowerCase(); - return cb.like(cb.lower(targetFilterQueryRoot.get(TargetFilterQuery_.name)), searchTextToLower); + return cb.like(cb.lower(targetFilterQueryRoot.get(JpaTargetFilterQuery_.name)), searchTextToLower); }; } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/TargetSpecifications.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetSpecifications.java similarity index 59% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/TargetSpecifications.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetSpecifications.java index de894d3a3..6571f8668 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/TargetSpecifications.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetSpecifications.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.specifications; +package org.eclipse.hawkbit.repository.jpa.specifications; import java.util.Collection; import java.util.List; @@ -20,15 +20,19 @@ import javax.persistence.criteria.Root; import javax.persistence.criteria.SetJoin; import javax.validation.constraints.NotNull; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag_; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSet_; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.hawkbit.repository.model.TargetInfo_; import org.eclipse.hawkbit.repository.model.TargetTag; -import org.eclipse.hawkbit.repository.model.TargetTag_; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.repository.model.Target_; import org.springframework.data.jpa.domain.Specification; /** @@ -50,10 +54,11 @@ public final class TargetSpecifications { * * @return the {@link Target} {@link Specification} */ - public static Specification byControllerIdWithStatusAndTagsInJoin(final Collection controllerIDs) { + public static Specification byControllerIdWithStatusAndTagsInJoin( + final Collection controllerIDs) { return (targetRoot, query, cb) -> { - final Predicate predicate = targetRoot.get(Target_.controllerId).in(controllerIDs); - targetRoot.fetch(Target_.tags, JoinType.LEFT); + final Predicate predicate = targetRoot.get(JpaTarget_.controllerId).in(controllerIDs); + targetRoot.fetch(JpaTarget_.tags, JoinType.LEFT); query.distinct(true); return predicate; }; @@ -68,12 +73,12 @@ public final class TargetSpecifications { * * @return the {@link Target} {@link Specification} */ - public static Specification byControllerIdWithStatusAndAssignedInJoin( + public static Specification byControllerIdWithStatusAndAssignedInJoin( final Collection controllerIDs) { return (targetRoot, query, cb) -> { - final Predicate predicate = targetRoot.get(Target_.controllerId).in(controllerIDs); - targetRoot.fetch(Target_.assignedDistributionSet); + final Predicate predicate = targetRoot.get(JpaTarget_.controllerId).in(controllerIDs); + targetRoot.fetch(JpaTarget_.assignedDistributionSet); return predicate; }; } @@ -89,19 +94,19 @@ public final class TargetSpecifications { * join it. * @return the {@link Target} {@link Specification} */ - public static Specification hasTargetUpdateStatus(final Collection updateStatus, + public static Specification hasTargetUpdateStatus(final Collection updateStatus, final boolean fetch) { return (targetRoot, query, cb) -> { if (!query.getResultType().isAssignableFrom(Long.class)) { if (fetch) { - targetRoot.fetch(Target_.targetInfo); + targetRoot.fetch(JpaTarget_.targetInfo); } else { - targetRoot.join(Target_.targetInfo); + targetRoot.join(JpaTarget_.targetInfo); } - return targetRoot.get(Target_.targetInfo).get(TargetInfo_.updateStatus).in(updateStatus); + return targetRoot.get(JpaTarget_.targetInfo).get(JpaTargetInfo_.updateStatus).in(updateStatus); } - final Join targetInfoJoin = targetRoot.join(Target_.targetInfo); - return targetInfoJoin.get(TargetInfo_.updateStatus).in(updateStatus); + final Join targetInfoJoin = targetRoot.join(JpaTarget_.targetInfo); + return targetInfoJoin.get(JpaTargetInfo_.updateStatus).in(updateStatus); }; } @@ -113,11 +118,11 @@ public final class TargetSpecifications { * to be filtered on * @return the {@link Target} {@link Specification} */ - public static Specification likeNameOrDescriptionOrIp(final String searchText) { + public static Specification likeNameOrDescriptionOrIp(final String searchText) { return (targetRoot, query, cb) -> { final String searchTextToLower = searchText.toLowerCase(); - return cb.or(cb.like(cb.lower(targetRoot.get(Target_.name)), searchTextToLower), - cb.like(cb.lower(targetRoot.get(Target_.description)), searchTextToLower)); + return cb.or(cb.like(cb.lower(targetRoot.get(JpaTarget_.name)), searchTextToLower), + cb.like(cb.lower(targetRoot.get(JpaTarget_.description)), searchTextToLower)); }; } @@ -129,14 +134,14 @@ public final class TargetSpecifications { * to be filtered on * @return the {@link Target} {@link Specification} */ - public static Specification hasInstalledOrAssignedDistributionSet(@NotNull final Long distributionId) { + public static Specification hasInstalledOrAssignedDistributionSet(@NotNull final Long distributionId) { return (targetRoot, query, cb) -> { - final Join targetInfoJoin = targetRoot.join(Target_.targetInfo); + final Join targetInfoJoin = targetRoot.join(JpaTarget_.targetInfo); return cb.or( - cb.equal(targetInfoJoin.get(TargetInfo_.installedDistributionSet).get(DistributionSet_.id), + cb.equal(targetInfoJoin.get(JpaTargetInfo_.installedDistributionSet).get(JpaDistributionSet_.id), distributionId), - cb.equal(targetRoot. get(Target_.assignedDistributionSet).get(DistributionSet_.id), - distributionId)); + cb.equal(targetRoot. get(JpaTarget_.assignedDistributionSet) + .get(JpaDistributionSet_.id), distributionId)); }; } @@ -150,13 +155,12 @@ public final class TargetSpecifications { * set that is not yet assigned * @return the {@link Target} {@link Specification} */ - public static Specification hasControllerIdAndAssignedDistributionSetIdNot(final List tIDs, + public static Specification hasControllerIdAndAssignedDistributionSetIdNot(final List tIDs, @NotNull final Long distributionId) { - return (targetRoot, query, cb) -> cb - .and(targetRoot.get(Target_.controllerId).in(tIDs), - cb.or(cb.notEqual(targetRoot. get(Target_.assignedDistributionSet) - .get(DistributionSet_.id), distributionId), - cb.isNull(targetRoot. get(Target_.assignedDistributionSet)))); + return (targetRoot, query, cb) -> cb.and(targetRoot.get(JpaTarget_.controllerId).in(tIDs), + cb.or(cb.notEqual(targetRoot. get(JpaTarget_.assignedDistributionSet) + .get(JpaDistributionSet_.id), distributionId), + cb.isNull(targetRoot. get(JpaTarget_.assignedDistributionSet)))); } /** @@ -169,7 +173,7 @@ public final class TargetSpecifications { * flag to get targets with no tag assigned * @return the {@link Target} {@link Specification} */ - public static Specification hasTags(final String[] tagNames, final Boolean selectTargetWithNoTag) { + public static Specification hasTags(final String[] tagNames, final Boolean selectTargetWithNoTag) { return (targetRoot, query, cb) -> { final Predicate predicate = getPredicate(targetRoot, cb, selectTargetWithNoTag, tagNames); query.distinct(true); @@ -177,10 +181,10 @@ public final class TargetSpecifications { }; } - private static Predicate getPredicate(final Root targetRoot, final CriteriaBuilder cb, + private static Predicate getPredicate(final Root targetRoot, final CriteriaBuilder cb, final Boolean selectTargetWithNoTag, final String[] tagNames) { - final SetJoin tags = targetRoot.join(Target_.tags, JoinType.LEFT); - final Path exp = tags.get(TargetTag_.name); + final SetJoin tags = targetRoot.join(JpaTarget_.tags, JoinType.LEFT); + final Path exp = tags.get(JpaTargetTag_.name); if (selectTargetWithNoTag) { if (tagNames != null) { return cb.or(exp.isNull(), exp.in(tagNames)); @@ -200,9 +204,9 @@ public final class TargetSpecifications { * the ID of the distribution set which must be assigned * @return the {@link Target} {@link Specification} */ - public static Specification hasAssignedDistributionSet(final Long distributionSetId) { + public static Specification hasAssignedDistributionSet(final Long distributionSetId) { return (targetRoot, query, cb) -> cb.equal( - targetRoot. get(Target_.assignedDistributionSet).get(DistributionSet_.id), + targetRoot. get(JpaTarget_.assignedDistributionSet).get(JpaDistributionSet_.id), distributionSetId); } @@ -214,10 +218,10 @@ public final class TargetSpecifications { * the ID of the distribution set which must be assigned * @return the {@link Target} {@link Specification} */ - public static Specification hasInstalledDistributionSet(final Long distributionSetId) { + public static Specification hasInstalledDistributionSet(final Long distributionSetId) { return (targetRoot, query, cb) -> { - final Join targetInfoJoin = targetRoot.join(Target_.targetInfo); - return cb.equal(targetInfoJoin.get(TargetInfo_.installedDistributionSet).get(DistributionSet_.id), + final Join targetInfoJoin = targetRoot.join(JpaTarget_.targetInfo); + return cb.equal(targetInfoJoin.get(JpaTargetInfo_.installedDistributionSet).get(JpaDistributionSet_.id), distributionSetId); }; } diff --git a/hawkbit-repository/src/main/resources/db/migration/H2/V1_0_1__init___H2.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_0_1__init___H2.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/H2/V1_0_1__init___H2.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_0_1__init___H2.sql diff --git a/hawkbit-repository/src/main/resources/db/migration/H2/V1_2_0__update_target_info_for_message___H2.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_2_0__update_target_info_for_message___H2.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/H2/V1_2_0__update_target_info_for_message___H2.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_2_0__update_target_info_for_message___H2.sql diff --git a/hawkbit-repository/src/main/resources/db/migration/H2/V1_4_0__cascade_delete___H2.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_4_0__cascade_delete___H2.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/H2/V1_4_0__cascade_delete___H2.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_4_0__cascade_delete___H2.sql diff --git a/hawkbit-repository/src/main/resources/db/migration/H2/V1_4_1__cascade_delete___H2.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_4_1__cascade_delete___H2.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/H2/V1_4_1__cascade_delete___H2.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_4_1__cascade_delete___H2.sql diff --git a/hawkbit-repository/src/main/resources/db/migration/H2/V1_5_0__target_filter_query___H2.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_5_0__target_filter_query___H2.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/H2/V1_5_0__target_filter_query___H2.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_5_0__target_filter_query___H2.sql diff --git a/hawkbit-repository/src/main/resources/db/migration/H2/V1_6_0__rollout_management___H2.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_6_0__rollout_management___H2.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/H2/V1_6_0__rollout_management___H2.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_6_0__rollout_management___H2.sql diff --git a/hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_0_1__init___MYSQL.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_0_1__init___MYSQL.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_0_1__init___MYSQL.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_0_1__init___MYSQL.sql diff --git a/hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_2_0__update_target_info_for_message___MYSQL.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_2_0__update_target_info_for_message___MYSQL.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_2_0__update_target_info_for_message___MYSQL.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_2_0__update_target_info_for_message___MYSQL.sql diff --git a/hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_4_0__cascade_delete___MYSQL.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_4_0__cascade_delete___MYSQL.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_4_0__cascade_delete___MYSQL.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_4_0__cascade_delete___MYSQL.sql diff --git a/hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_4_1__cascade_delete___MYSQL.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_4_1__cascade_delete___MYSQL.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_4_1__cascade_delete___MYSQL.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_4_1__cascade_delete___MYSQL.sql diff --git a/hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_5_0__target_filter_query___MYSQL.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_5_0__target_filter_query___MYSQL.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_5_0__target_filter_query___MYSQL.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_5_0__target_filter_query___MYSQL.sql diff --git a/hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_6_0__rollout_management___MYSQL.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_6_0__rollout_management___MYSQL.sql similarity index 100% rename from hawkbit-repository/src/main/resources/db/migration/MYSQL/V1_6_0__rollout_management___MYSQL.sql rename to hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_6_0__rollout_management___MYSQL.sql diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java new file mode 100644 index 000000000..45831d08f --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +import org.eclipse.hawkbit.cache.TenantAwareCacheManager; +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.data.mongodb.gridfs.GridFsOperations; + +@SpringApplicationConfiguration(classes = { org.eclipse.hawkbit.RepositoryApplicationConfiguration.class }) +public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest { + + @PersistenceContext + protected EntityManager entityManager; + + @Autowired + protected TargetRepository targetRepository; + + @Autowired + protected ActionRepository actionRepository; + + @Autowired + protected DistributionSetRepository distributionSetRepository; + + @Autowired + protected SoftwareModuleRepository softwareModuleRepository; + + @Autowired + protected TenantMetaDataRepository tenantMetaDataRepository; + + @Autowired + protected DistributionSetTypeRepository distributionSetTypeRepository; + + @Autowired + protected SoftwareModuleTypeRepository softwareModuleTypeRepository; + + @Autowired + protected TargetTagRepository targetTagRepository; + + @Autowired + protected DistributionSetTagRepository distributionSetTagRepository; + + @Autowired + protected SoftwareModuleMetadataRepository softwareModuleMetadataRepository; + + @Autowired + protected ActionStatusRepository actionStatusRepository; + + @Autowired + protected ExternalArtifactRepository externalArtifactRepository; + + @Autowired + protected LocalArtifactRepository artifactRepository; + + @Autowired + protected TargetInfoRepository targetInfoRepository; + + @Autowired + protected GridFsOperations operations; + + @Autowired + protected RolloutGroupRepository rolloutGroupRepository; + + @Autowired + protected RolloutRepository rolloutRepository; + + @Autowired + protected TenantAwareCacheManager cacheManager; +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTestWithMongoDB.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTestWithMongoDB.java new file mode 100644 index 000000000..e2e755246 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTestWithMongoDB.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +import org.eclipse.hawkbit.cache.TenantAwareCacheManager; +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.SpringApplicationConfiguration; + +@SpringApplicationConfiguration(classes = { org.eclipse.hawkbit.RepositoryApplicationConfiguration.class }) +public abstract class AbstractJpaIntegrationTestWithMongoDB extends AbstractIntegrationTestWithMongoDB { + + @PersistenceContext + protected EntityManager entityManager; + + @Autowired + protected TargetRepository targetRepository; + + @Autowired + protected ActionRepository actionRepository; + + @Autowired + protected DistributionSetRepository distributionSetRepository; + + @Autowired + protected SoftwareModuleRepository softwareModuleRepository; + + @Autowired + protected TenantMetaDataRepository tenantMetaDataRepository; + + @Autowired + protected DistributionSetTypeRepository distributionSetTypeRepository; + + @Autowired + protected SoftwareModuleTypeRepository softwareModuleTypeRepository; + + @Autowired + protected TargetTagRepository targetTagRepository; + + @Autowired + protected DistributionSetTagRepository distributionSetTagRepository; + + @Autowired + protected SoftwareModuleMetadataRepository softwareModuleMetadataRepository; + + @Autowired + protected ActionStatusRepository actionStatusRepository; + + @Autowired + protected ExternalArtifactRepository externalArtifactRepository; + + @Autowired + protected LocalArtifactRepository artifactRepository; + + @Autowired + protected TargetInfoRepository targetInfoRepository; + + @Autowired + protected RolloutGroupRepository rolloutGroupRepository; + + @Autowired + protected RolloutRepository rolloutRepository; + + @Autowired + protected TenantAwareCacheManager cacheManager; + +} diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ActionTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ActionTest.java similarity index 87% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ActionTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ActionTest.java index 937a544a7..9104f28cf 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ActionTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ActionTest.java @@ -6,11 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; -import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.junit.Test; @@ -26,11 +26,11 @@ public class ActionTest { @Description("Ensures that timeforced moded switch from soft to forces after defined timeframe.") public void timeforcedHitNewHasCodeIsGenerated() throws InterruptedException { - final boolean active = true; + final boolean active; // current time + 1 seconds final long sleepTime = 1000; final long timeForceTimeAt = System.currentTimeMillis() + sleepTime; - final Action timeforcedAction = new Action(); + final JpaAction timeforcedAction = new JpaAction(); timeforcedAction.setActionType(ActionType.TIMEFORCED); timeforcedAction.setForcedTime(timeForceTimeAt); assertThat(timeforcedAction.isForce()).isFalse(); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ArtifactManagementNoMongoDbTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementNoMongoDbTest.java similarity index 84% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ArtifactManagementNoMongoDbTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementNoMongoDbTest.java index 30f4093c2..42b759b74 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ArtifactManagementNoMongoDbTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementNoMongoDbTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.junit.Assert.fail; @@ -14,9 +14,8 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import org.apache.commons.lang3.RandomStringUtils; -import org.eclipse.hawkbit.AbstractIntegrationTest; import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException; -import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.junit.BeforeClass; import org.junit.Test; @@ -30,7 +29,7 @@ import ru.yandex.qatools.allure.annotations.Stories; */ @Features("Component Tests - Repository") @Stories("Artifact Management") -public class ArtifactManagementNoMongoDbTest extends AbstractIntegrationTest { +public class ArtifactManagementNoMongoDbTest extends AbstractJpaIntegrationTest { @BeforeClass public static void initialize() { @@ -42,7 +41,7 @@ public class ArtifactManagementNoMongoDbTest extends AbstractIntegrationTest { @Test @Description("Checks if the expected ArtifactUploadFailedException is thrown in case of MongoDB down") public void createLocalArtifactWithMongoDbDown() throws IOException { - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", + JpaSoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareModuleRepository.save(sm); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ArtifactManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementTest.java similarity index 73% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ArtifactManagementTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementTest.java index 7c801a571..293dcdf91 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ArtifactManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.assertNotNull; @@ -20,18 +20,20 @@ import java.security.NoSuchAlgorithmException; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomStringUtils; -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; -import org.eclipse.hawkbit.HashGeneratorUtils; -import org.eclipse.hawkbit.RandomGeneratedInputStream; -import org.eclipse.hawkbit.WithUser; import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.exception.ArtifactDeleteFailedException; import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; +import org.eclipse.hawkbit.repository.jpa.model.JpaExternalArtifact; +import org.eclipse.hawkbit.repository.jpa.model.JpaExternalArtifactProvider; +import org.eclipse.hawkbit.repository.jpa.model.JpaLocalArtifact; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.model.Artifact; -import org.eclipse.hawkbit.repository.model.ExternalArtifact; import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.test.util.HashGeneratorUtils; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.Test; import org.slf4j.LoggerFactory; import org.springframework.data.mongodb.core.query.Criteria; @@ -50,7 +52,7 @@ import ru.yandex.qatools.allure.annotations.Stories; */ @Features("Component Tests - Repository") @Stories("Artifact Management") -public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { +public class ArtifactManagementTest extends AbstractJpaIntegrationTestWithMongoDB { public ArtifactManagementTest() { LOG = LoggerFactory.getLogger(ArtifactManagementTest.class); } @@ -70,15 +72,15 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { assertThat(softwareModuleRepository.findAll()).hasSize(0); assertThat(artifactRepository.findAll()).hasSize(0); - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", + JpaSoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareModuleRepository.save(sm); - SoftwareModule sm2 = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 2", + JpaSoftwareModule sm2 = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 2", "version 2", null, null); sm2 = softwareModuleRepository.save(sm2); - SoftwareModule sm3 = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 3", + JpaSoftwareModule sm3 = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 3", "version 3", null, null); sm3 = softwareModuleRepository.save(sm3); @@ -96,11 +98,11 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { assertThat(result).isInstanceOf(LocalArtifact.class); assertThat(result.getSoftwareModule().getId()).isEqualTo(sm.getId()); assertThat(result2.getSoftwareModule().getId()).isEqualTo(sm2.getId()); - assertThat(((LocalArtifact) result).getFilename()).isEqualTo("file1"); - assertThat(((LocalArtifact) result).getGridFsFileName()).isNotNull(); + assertThat(((JpaLocalArtifact) result).getFilename()).isEqualTo("file1"); + assertThat(((JpaLocalArtifact) result).getGridFsFileName()).isNotNull(); assertThat(result).isNotEqualTo(result2); - assertThat(((LocalArtifact) result).getGridFsFileName()) - .isEqualTo(((LocalArtifact) result2).getGridFsFileName()); + assertThat(((JpaLocalArtifact) result).getGridFsFileName()) + .isEqualTo(((JpaLocalArtifact) result2).getGridFsFileName()); assertThat(artifactManagement.findLocalArtifactByFilename("file1").get(0).getSha1Hash()) .isEqualTo(HashGeneratorUtils.generateSHA1(random)); @@ -116,7 +118,7 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Tests hard delete directly on repository.") public void hardDeleteSoftwareModule() throws NoSuchAlgorithmException, IOException { - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", + JpaSoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareModuleRepository.save(sm); @@ -137,18 +139,19 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Tests the creation of an external artifact metadata element.") public void createExternalArtifact() { - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", + JpaSoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareModuleRepository.save(sm); - SoftwareModule sm2 = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 2", + JpaSoftwareModule sm2 = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 2", "version 2", null, null); sm2 = softwareModuleRepository.save(sm2); final ExternalArtifactProvider provider = artifactManagement.createExternalArtifactProvider("provider X", null, "https://fhghdfjgh", "/{version}/"); - ExternalArtifact result = artifactManagement.createExternalArtifact(provider, null, sm.getId()); + JpaExternalArtifact result = (JpaExternalArtifact) artifactManagement.createExternalArtifact(provider, null, + sm.getId()); assertNotNull("The result of an external artifact should not be null", result); assertThat(externalArtifactRepository.findAll()).contains(result).hasSize(1); @@ -156,7 +159,7 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { assertThat(result.getUrl()).isEqualTo("https://fhghdfjgh/{version}/"); assertThat(result.getExternalArtifactProvider()).isEqualTo(provider); - result = artifactManagement.createExternalArtifact(provider, "/test", sm2.getId()); + result = (JpaExternalArtifact) artifactManagement.createExternalArtifact(provider, "/test", sm2.getId()); assertNotNull("The newly created external artifact should not be null", result); assertThat(externalArtifactRepository.findAll()).contains(result).hasSize(2); assertThat(result.getUrl()).isEqualTo("https://fhghdfjgh/test"); @@ -168,14 +171,15 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { public void deleteExternalArtifact() { assertThat(artifactRepository.findAll()).isEmpty(); - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", + JpaSoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareModuleRepository.save(sm); - final ExternalArtifactProvider provider = artifactManagement.createExternalArtifactProvider("provider X", null, - "https://fhghdfjgh", "/{version}/"); + final JpaExternalArtifactProvider provider = (JpaExternalArtifactProvider) artifactManagement + .createExternalArtifactProvider("provider X", null, "https://fhghdfjgh", "/{version}/"); - final ExternalArtifact result = artifactManagement.createExternalArtifact(provider, null, sm.getId()); + final JpaExternalArtifact result = (JpaExternalArtifact) artifactManagement.createExternalArtifact(provider, + null, sm.getId()); assertNotNull("The newly created external artifact should not be null", result); assertThat(externalArtifactRepository.findAll()).contains(result).hasSize(1); @@ -194,11 +198,11 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Tests the deletion of a local artifact including metadata.") public void deleteLocalArtifact() throws NoSuchAlgorithmException, IOException { - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", + JpaSoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareModuleRepository.save(sm); - SoftwareModule sm2 = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 2", + JpaSoftwareModule sm2 = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 2", "version 2", null, null); sm2 = softwareModuleRepository.save(sm2); @@ -213,26 +217,25 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { assertThat(result.getId()).isNotNull(); assertThat(result2.getId()).isNotNull(); - assertThat(((LocalArtifact) result).getGridFsFileName()) - .isNotEqualTo(((LocalArtifact) result2).getGridFsFileName()); - assertThat(operations.findOne( - new Query().addCriteria(Criteria.where("filename").is(((LocalArtifact) result).getGridFsFileName())))) + assertThat(((JpaLocalArtifact) result).getGridFsFileName()) + .isNotEqualTo(((JpaLocalArtifact) result2).getGridFsFileName()); + assertThat(operations.findOne(new Query() + .addCriteria(Criteria.where("filename").is(((JpaLocalArtifact) result).getGridFsFileName())))) .isNotNull(); - assertThat(operations.findOne( - new Query().addCriteria(Criteria.where("filename").is(((LocalArtifact) result2).getGridFsFileName())))) + assertThat(operations.findOne(new Query() + .addCriteria(Criteria.where("filename").is(((JpaLocalArtifact) result2).getGridFsFileName())))) .isNotNull(); artifactManagement.deleteLocalArtifact(result.getId()); - assertThat(operations.findOne( - new Query().addCriteria(Criteria.where("filename").is(((LocalArtifact) result).getGridFsFileName())))) - .isNull(); - assertThat(operations.findOne( - new Query().addCriteria(Criteria.where("filename").is(((LocalArtifact) result2).getGridFsFileName())))) + assertThat(operations.findOne(new Query() + .addCriteria(Criteria.where("filename").is(((JpaLocalArtifact) result).getGridFsFileName())))).isNull(); + assertThat(operations.findOne(new Query() + .addCriteria(Criteria.where("filename").is(((JpaLocalArtifact) result2).getGridFsFileName())))) .isNotNull(); artifactManagement.deleteLocalArtifact(result2.getId()); - assertThat(operations.findOne( - new Query().addCriteria(Criteria.where("filename").is(((LocalArtifact) result2).getGridFsFileName())))) + assertThat(operations.findOne(new Query() + .addCriteria(Criteria.where("filename").is(((JpaLocalArtifact) result2).getGridFsFileName())))) .isNull(); assertThat(artifactRepository.findAll()).hasSize(0); @@ -245,7 +248,7 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { assertThat(artifactRepository.findAll()).isEmpty(); // prepare test - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", + JpaSoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareModuleRepository.save(sm); @@ -272,11 +275,11 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Test the deletion of an artifact metadata where the binary is still linked to another " + "metadata element. The expected result is that the metadata is deleted but the binary kept.") public void deleteDuplicateArtifacts() throws NoSuchAlgorithmException, IOException { - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", + JpaSoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareModuleRepository.save(sm); - SoftwareModule sm2 = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 2", + JpaSoftwareModule sm2 = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 2", "version 2", null, null); sm2 = softwareModuleRepository.save(sm2); @@ -290,21 +293,20 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { assertThat(artifactRepository.findAll()).hasSize(2); assertThat(result.getId()).isNotNull(); assertThat(result2.getId()).isNotNull(); - assertThat(((LocalArtifact) result).getGridFsFileName()) - .isEqualTo(((LocalArtifact) result2).getGridFsFileName()); + assertThat(((JpaLocalArtifact) result).getGridFsFileName()) + .isEqualTo(((JpaLocalArtifact) result2).getGridFsFileName()); - assertThat(operations.findOne( - new Query().addCriteria(Criteria.where("filename").is(((LocalArtifact) result).getGridFsFileName())))) + assertThat(operations.findOne(new Query() + .addCriteria(Criteria.where("filename").is(((JpaLocalArtifact) result).getGridFsFileName())))) .isNotNull(); artifactManagement.deleteLocalArtifact(result.getId()); - assertThat(operations.findOne( - new Query().addCriteria(Criteria.where("filename").is(((LocalArtifact) result).getGridFsFileName())))) + assertThat(operations.findOne(new Query() + .addCriteria(Criteria.where("filename").is(((JpaLocalArtifact) result).getGridFsFileName())))) .isNotNull(); artifactManagement.deleteLocalArtifact(result2.getId()); - assertThat(operations.findOne( - new Query().addCriteria(Criteria.where("filename").is(((LocalArtifact) result).getGridFsFileName())))) - .isNull(); + assertThat(operations.findOne(new Query() + .addCriteria(Criteria.where("filename").is(((JpaLocalArtifact) result).getGridFsFileName())))).isNull(); } /** @@ -318,7 +320,7 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Loads an artifact based on given ID.") public void findArtifact() throws NoSuchAlgorithmException, IOException { - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", + SoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); @@ -339,7 +341,7 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Loads an artifact binary based on given ID.") public void loadStreamOfLocalArtifact() throws NoSuchAlgorithmException, IOException { - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", + SoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); @@ -357,7 +359,7 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Trys and fails to load an artifact without required permission. Checks if expected InsufficientPermissionException is thrown.") public void loadLocalArtifactBinaryWithoutDownloadArtifactThrowsPermissionDenied() { try { - artifactManagement.loadLocalArtifactBinary(new LocalArtifact()); + artifactManagement.loadLocalArtifactBinary(new JpaLocalArtifact()); fail("Should not have worked with missing permission."); } catch (final InsufficientPermissionException e) { @@ -367,10 +369,10 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Searches an artifact through the relations of a software module.") public void findLocalArtifactBySoftwareModule() { - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = new JpaSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); - SoftwareModule sm2 = new SoftwareModule(osType, "name 2", "version 2", null, null); + SoftwareModule sm2 = new JpaSoftwareModule(osType, "name 2", "version 2", null, null); sm2 = softwareManagement.createSoftwareModule(sm2); assertThat(artifactManagement.findLocalArtifactBySoftwareModule(pageReq, sm.getId())).isEmpty(); @@ -384,7 +386,7 @@ public class ArtifactManagementTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Searches an artifact through the relations of a software module and the filename.") public void findByFilenameAndSoftwareModule() { - SoftwareModule sm = new SoftwareModule(osType, "name 1", "version 1", null, null); + SoftwareModule sm = new JpaSoftwareModule(osType, "name 1", "version 1", null, null); sm = softwareManagement.createSoftwareModule(sm); assertThat(artifactManagement.findByFilenameAndSoftwareModule("file1", sm.getId())).isEmpty(); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ControllerManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ControllerManagementTest.java new file mode 100644 index 000000000..77adfa45b --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ControllerManagementTest.java @@ -0,0 +1,224 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import static org.fest.assertions.api.Assertions.assertThat; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; + +import javax.validation.ConstraintViolationException; + +import org.apache.commons.lang3.RandomStringUtils; +import org.eclipse.hawkbit.repository.RepositoryProperties; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import ru.yandex.qatools.allure.annotations.Description; +import ru.yandex.qatools.allure.annotations.Features; +import ru.yandex.qatools.allure.annotations.Stories; + +@Features("Component Tests - Repository") +@Stories("Controller Management") +public class ControllerManagementTest extends AbstractJpaIntegrationTest { + @Autowired + private RepositoryProperties repositoryProperties; + + @Test + @Description("Controller adds a new action status.") + public void controllerAddsActionStatus() { + final Target target = new JpaTarget("4712"); + final DistributionSet ds = testdataFactory.createDistributionSet(""); + Target savedTarget = targetManagement.createTarget(target); + + final List toAssign = new ArrayList<>(); + toAssign.add(savedTarget); + + assertThat(savedTarget.getTargetInfo().getUpdateStatus()).isEqualTo(TargetUpdateStatus.UNKNOWN); + + savedTarget = deploymentManagement.assignDistributionSet(ds, toAssign).getAssignedEntity().iterator().next(); + final Action savedAction = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); + + assertThat(targetManagement.findTargetByControllerID(savedTarget.getControllerId()).getTargetInfo() + .getUpdateStatus()).isEqualTo(TargetUpdateStatus.PENDING); + + ActionStatus actionStatusMessage = new JpaActionStatus(savedAction, Action.Status.RUNNING, + System.currentTimeMillis()); + actionStatusMessage.addMessage("foobar"); + savedAction.setStatus(Status.RUNNING); + controllerManagament.addUpdateActionStatus(actionStatusMessage); + assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getUpdateStatus()) + .isEqualTo(TargetUpdateStatus.PENDING); + + actionStatusMessage = new JpaActionStatus(savedAction, Action.Status.FINISHED, System.currentTimeMillis()); + actionStatusMessage.addMessage(RandomStringUtils.randomAscii(512)); + savedAction.setStatus(Status.FINISHED); + controllerManagament.addUpdateActionStatus(actionStatusMessage); + assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getUpdateStatus()) + .isEqualTo(TargetUpdateStatus.IN_SYNC); + + assertThat(actionStatusRepository.findAll(pageReq).getNumberOfElements()).isEqualTo(3); + assertThat(deploymentManagement.findActionStatusByAction(pageReq, savedAction).getNumberOfElements()) + .isEqualTo(3); + } + + @Test + @Description("Register a controller which does not exist") + public void testfindOrRegisterTargetIfItDoesNotexist() { + final Target target = controllerManagament.findOrRegisterTargetIfItDoesNotexist("AA", null); + assertThat(target).as("target should not be null").isNotNull(); + + final Target sameTarget = controllerManagament.findOrRegisterTargetIfItDoesNotexist("AA", null); + assertThat(target).as("Target should be the equals").isEqualTo(sameTarget); + assertThat(targetRepository.count()).as("Only 1 target should be registred").isEqualTo(1L); + + // throws exception + try { + controllerManagament.findOrRegisterTargetIfItDoesNotexist("", null); + fail("should fail as target does not exist"); + } catch (final ConstraintViolationException e) { + + } + } + + @Test + @Description("Controller trys to finish an update process after it has been finished by an error action status.") + public void tryToFinishUpdateProcessMoreThanOnce() { + + // mock + final Target target = new JpaTarget("Rabbit"); + final DistributionSet ds = testdataFactory.createDistributionSet(""); + Target savedTarget = targetManagement.createTarget(target); + final List toAssign = new ArrayList<>(); + toAssign.add(savedTarget); + savedTarget = deploymentManagement.assignDistributionSet(ds, toAssign).getAssignedEntity().iterator().next(); + Action savedAction = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); + + // test and verify + final ActionStatus actionStatusMessage = new JpaActionStatus(savedAction, Action.Status.RUNNING, + System.currentTimeMillis()); + actionStatusMessage.addMessage("running"); + savedAction = controllerManagament.addUpdateActionStatus(actionStatusMessage); + assertThat(targetManagement.findTargetByControllerID("Rabbit").getTargetInfo().getUpdateStatus()) + .isEqualTo(TargetUpdateStatus.PENDING); + + final ActionStatus actionStatusMessage2 = new JpaActionStatus(savedAction, Action.Status.ERROR, + System.currentTimeMillis()); + actionStatusMessage2.addMessage("error"); + savedAction = controllerManagament.addUpdateActionStatus(actionStatusMessage2); + assertThat(targetManagement.findTargetByControllerID("Rabbit").getTargetInfo().getUpdateStatus()) + .isEqualTo(TargetUpdateStatus.ERROR); + + // try with disabled late feedback + repositoryProperties.setRejectActionStatusForClosedAction(true); + final ActionStatus actionStatusMessage3 = new JpaActionStatus(savedAction, Action.Status.FINISHED, + System.currentTimeMillis()); + actionStatusMessage3.addMessage("finish"); + savedAction = controllerManagament.addUpdateActionStatus(actionStatusMessage3); + + // test + assertThat(targetManagement.findTargetByControllerID("Rabbit").getTargetInfo().getUpdateStatus()) + .isEqualTo(TargetUpdateStatus.ERROR); + + // try with enabled late feedback + repositoryProperties.setRejectActionStatusForClosedAction(false); + final ActionStatus actionStatusMessage4 = new JpaActionStatus(savedAction, Action.Status.FINISHED, + System.currentTimeMillis()); + actionStatusMessage4.addMessage("finish"); + controllerManagament.addUpdateActionStatus(actionStatusMessage3); + + // test + assertThat(targetManagement.findTargetByControllerID("Rabbit").getTargetInfo().getUpdateStatus()) + .isEqualTo(TargetUpdateStatus.ERROR); + + } + + @Test + @Description("Controller trys to send an update feedback after it has been finished which is reject as the repository is " + + "configured to reject that.") + public void sendUpdatesForFinishUpdateProcessDropedIfDisabled() { + repositoryProperties.setRejectActionStatusForClosedAction(true); + + final Action action = prepareFinishedUpdate("Rabbit"); + + final ActionStatus actionStatusMessage1 = new JpaActionStatus(action, Action.Status.RUNNING, + System.currentTimeMillis()); + actionStatusMessage1.addMessage("got some additional feedback"); + controllerManagament.addUpdateActionStatus(actionStatusMessage1); + + // nothing changed as "feedback after close" is disabled + assertThat(targetManagement.findTargetByControllerID("Rabbit").getTargetInfo().getUpdateStatus()) + .isEqualTo(TargetUpdateStatus.IN_SYNC); + assertThat(actionStatusRepository.findAll(pageReq).getNumberOfElements()).isEqualTo(3); + assertThat(deploymentManagement.findActionStatusByAction(pageReq, action).getNumberOfElements()).isEqualTo(3); + } + + @Test + @Description("Controller trys to send an update feedback after it has been finished which is actepted as the repository is " + + "configured to accept them.") + public void sendUpdatesForFinishUpdateProcessAcceptedIfEnabled() { + repositoryProperties.setRejectActionStatusForClosedAction(false); + + Action action = prepareFinishedUpdate("Rabbit"); + + final ActionStatus actionStatusMessage1 = new JpaActionStatus(action, Action.Status.RUNNING, + System.currentTimeMillis()); + actionStatusMessage1.addMessage("got some additional feedback"); + action = controllerManagament.addUpdateActionStatus(actionStatusMessage1); + + // nothing changed as "feedback after close" is disabled + assertThat(targetManagement.findTargetByControllerID("Rabbit").getTargetInfo().getUpdateStatus()) + .isEqualTo(TargetUpdateStatus.IN_SYNC); + assertThat(actionStatusRepository.findAll(pageReq).getNumberOfElements()).isEqualTo(4); + assertThat(deploymentManagement.findActionStatusByAction(pageReq, action).getNumberOfElements()).isEqualTo(4); + } + + private Action prepareFinishedUpdate(final String controllerId) { + // mock + final Target target = new JpaTarget(controllerId); + final DistributionSet ds = testdataFactory.createDistributionSet(""); + Target savedTarget = targetManagement.createTarget(target); + final List toAssign = new ArrayList<>(); + toAssign.add(savedTarget); + savedTarget = deploymentManagement.assignDistributionSet(ds, toAssign).getAssignedEntity().iterator().next(); + Action savedAction = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); + + // test and verify + final ActionStatus actionStatusMessage = new JpaActionStatus(savedAction, Action.Status.RUNNING, + System.currentTimeMillis()); + actionStatusMessage.addMessage("running"); + savedAction = controllerManagament.addUpdateActionStatus(actionStatusMessage); + assertThat(targetManagement.findTargetByControllerID(controllerId).getTargetInfo().getUpdateStatus()) + .isEqualTo(TargetUpdateStatus.PENDING); + + final ActionStatus actionStatusMessage2 = new JpaActionStatus(savedAction, Action.Status.FINISHED, + System.currentTimeMillis()); + actionStatusMessage2.addMessage("finish"); + savedAction = controllerManagament.addUpdateActionStatus(actionStatusMessage2); + + // test + assertThat(targetManagement.findTargetByControllerID(controllerId).getTargetInfo().getUpdateStatus()) + .isEqualTo(TargetUpdateStatus.IN_SYNC); + + assertThat(actionStatusRepository.findAll(pageReq).getNumberOfElements()).isEqualTo(3); + assertThat(deploymentManagement.findActionStatusByAction(pageReq, savedAction).getNumberOfElements()) + .isEqualTo(3); + + return savedAction; + } +} diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/DeploymentManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java similarity index 84% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/DeploymentManagementTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java index a17054a3d..565513107 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/DeploymentManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java @@ -6,13 +6,14 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -20,13 +21,20 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.Constants; -import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent; -import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent; +import org.eclipse.hawkbit.repository.ActionStatusFields; +import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult; +import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException; import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException; +import org.eclipse.hawkbit.repository.jpa.configuration.Constants; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.Status; @@ -59,7 +67,7 @@ import ru.yandex.qatools.allure.annotations.Stories; */ @Features("Component Tests - Repository") @Stories("Deployment Management") -public class DeploymentManagementTest extends AbstractIntegrationTest { +public class DeploymentManagementTest extends AbstractJpaIntegrationTest { @Autowired private EventBus eventBus; @@ -67,9 +75,9 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { @Test @Description("Test verifies that the repistory retrieves the action including all defined (lazy) details.") public void findActionWithLazyDetails() { - final DistributionSet testDs = TestDataUtil.generateDistributionSet("TestDs", "1.0", softwareManagement, - distributionSetManagement, new ArrayList()); - final List testTarget = targetManagement.createTargets(TestDataUtil.generateTargets(1)); + final DistributionSet testDs = testdataFactory.createDistributionSet("TestDs", "1.0", + new ArrayList()); + final List testTarget = testdataFactory.createTargets(1); // one action with one action status is generated final Long actionId = deploymentManagement.assignDistributionSet(testDs, testTarget).getActions().get(0); final Action action = deploymentManagement.findActionWithDetails(actionId); @@ -83,15 +91,15 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { @Test @Description("Test verifies that the custom query to find all actions include the count of action status is working correctly") public void findActionsWithStatusCountByTarget() { - final DistributionSet testDs = TestDataUtil.generateDistributionSet("TestDs", "1.0", softwareManagement, - distributionSetManagement, new ArrayList()); - final List testTarget = targetManagement.createTargets(TestDataUtil.generateTargets(1)); + final DistributionSet testDs = testdataFactory.createDistributionSet("TestDs", "1.0", + new ArrayList()); + final List testTarget = testdataFactory.createTargets(1); // one action with one action status is generated final Action action = deploymentManagement.findActionWithDetails( deploymentManagement.assignDistributionSet(testDs, testTarget).getActions().get(0)); // save 2 action status - actionStatusRepository.save(new ActionStatus(action, Status.RETRIEVED, System.currentTimeMillis())); - actionStatusRepository.save(new ActionStatus(action, Status.RUNNING, System.currentTimeMillis())); + actionStatusRepository.save(new JpaActionStatus(action, Status.RETRIEVED, System.currentTimeMillis())); + actionStatusRepository.save(new JpaActionStatus(action, Status.RUNNING, System.currentTimeMillis())); final List findActionsWithStatusCountByTarget = deploymentManagement .findActionsWithStatusCountByTargetOrderByIdDesc(testTarget.get(0)); @@ -104,14 +112,14 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { @Test @Description("Ensures that distribution sets can assigned and unassigned to a distribution set tag. Not exists distribution set will be ignored for the assignment.") public void assignAndUnassignDistributionSetToTag() { - final List assignDS = new ArrayList(); + final List assignDS = new ArrayList<>(); for (int i = 0; i < 4; i++) { - assignDS.add(TestDataUtil.generateDistributionSet("DS" + i, "1.0", softwareManagement, - distributionSetManagement, new ArrayList()).getId()); + assignDS.add(testdataFactory.createDistributionSet("DS" + i, "1.0", new ArrayList()) + .getId()); } // not exists assignDS.add(Long.valueOf(100)); - final DistributionSetTag tag = tagManagement.createDistributionSetTag(new DistributionSetTag("Tag1")); + final DistributionSetTag tag = tagManagement.createDistributionSetTag(new JpaDistributionSetTag("Tag1")); final List assignedDS = distributionSetManagement.assignTag(assignDS, tag); assertThat(assignedDS.size()).as("assigned ds has wrong size").isEqualTo(4); @@ -146,14 +154,13 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { @Description("Test verifies that an assignment with automatic cancelation works correctly even if the update is split into multiple partitions on the database.") public void multiAssigmentHistoryOverMultiplePagesResultsInTwoActiveAction() { - final DistributionSet cancelDs = TestDataUtil.generateDistributionSet("Canceled DS", "1.0", softwareManagement, - distributionSetManagement, new ArrayList()); + final DistributionSet cancelDs = testdataFactory.createDistributionSet("Canceled DS", "1.0", + new ArrayList()); - final DistributionSet cancelDs2 = TestDataUtil.generateDistributionSet("Canceled DS", "1.2", softwareManagement, - distributionSetManagement, new ArrayList()); + final DistributionSet cancelDs2 = testdataFactory.createDistributionSet("Canceled DS", "1.2", + new ArrayList()); - List targets = targetManagement - .createTargets(TestDataUtil.generateTargets(Constants.MAX_ENTRIES_IN_STATEMENT + 10)); + List targets = testdataFactory.createTargets(Constants.MAX_ENTRIES_IN_STATEMENT + 10); targets = deploymentManagement.assignDistributionSet(cancelDs, targets).getAssignedEntity(); targets = deploymentManagement.assignDistributionSet(cancelDs2, targets).getAssignedEntity(); @@ -170,17 +177,14 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { + "actions after canceling the second active action the first one is still running as it is not touched by the cancelation. After canceling the first one " + "also the target goes back to IN_SYNC as no open action is left.") public void manualCancelWithMultipleAssignmentsCancelLastOneFirst() { - Target target = new Target("4712"); - final DistributionSet dsFirst = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement, true); + JpaTarget target = new JpaTarget("4712"); + final DistributionSet dsFirst = testdataFactory.createDistributionSet("", true); dsFirst.setRequiredMigrationStep(true); - final DistributionSet dsSecond = TestDataUtil.generateDistributionSet("2", softwareManagement, - distributionSetManagement, true); - final DistributionSet dsInstalled = TestDataUtil.generateDistributionSet("installed", softwareManagement, - distributionSetManagement, true); + final DistributionSet dsSecond = testdataFactory.createDistributionSet("2", true); + final DistributionSet dsInstalled = testdataFactory.createDistributionSet("installed", true); - target.getTargetInfo().setInstalledDistributionSet(dsInstalled); - target = targetManagement.createTarget(target); + ((JpaTargetInfo) target.getTargetInfo()).setInstalledDistributionSet((JpaDistributionSet) dsInstalled); + target = (JpaTarget) targetManagement.createTarget(target); // check initial status assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getUpdateStatus()) @@ -199,8 +203,8 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { secondAction = deploymentManagement.findActionWithDetails(secondAction.getId()); // confirm cancellation secondAction.setStatus(Status.CANCELED); - controllerManagement.addCancelActionStatus( - new ActionStatus(secondAction, Status.CANCELED, System.currentTimeMillis()), secondAction); + controllerManagement + .addCancelActionStatus(new JpaActionStatus(secondAction, Status.CANCELED, System.currentTimeMillis())); assertThat(actionStatusRepository.findAll()).as("wrong size of actions status").hasSize(4); assertThat(targetManagement.findTargetByControllerID("4712").getAssignedDistributionSet()).as("wrong ds") .isEqualTo(dsFirst); @@ -213,8 +217,8 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { firstAction = deploymentManagement.findActionWithDetails(firstAction.getId()); // confirm cancellation firstAction.setStatus(Status.CANCELED); - controllerManagement.addCancelActionStatus( - new ActionStatus(firstAction, Status.CANCELED, System.currentTimeMillis()), firstAction); + controllerManagement + .addCancelActionStatus(new JpaActionStatus(firstAction, Status.CANCELED, System.currentTimeMillis())); assertThat(actionStatusRepository.findAll()).as("wrong size of action status").hasSize(6); assertThat(targetManagement.findTargetByControllerID("4712").getAssignedDistributionSet()) .as("wrong assigned ds").isEqualTo(dsInstalled); @@ -227,17 +231,14 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { + "actions after canceling the first active action the system switched to second one. After canceling this one " + "also the target goes back to IN_SYNC as no open action is left.") public void manualCancelWithMultipleAssignmentsCancelMiddleOneFirst() { - Target target = new Target("4712"); - final DistributionSet dsFirst = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement, true); + JpaTarget target = new JpaTarget("4712"); + final DistributionSet dsFirst = testdataFactory.createDistributionSet("", true); dsFirst.setRequiredMigrationStep(true); - final DistributionSet dsSecond = TestDataUtil.generateDistributionSet("2", softwareManagement, - distributionSetManagement, true); - final DistributionSet dsInstalled = TestDataUtil.generateDistributionSet("installed", softwareManagement, - distributionSetManagement, true); + final DistributionSet dsSecond = testdataFactory.createDistributionSet("2", true); + final DistributionSet dsInstalled = testdataFactory.createDistributionSet("installed", true); - target.getTargetInfo().setInstalledDistributionSet(dsInstalled); - target = targetManagement.createTarget(target); + ((JpaTargetInfo) target.getTargetInfo()).setInstalledDistributionSet((JpaDistributionSet) dsInstalled); + target = (JpaTarget) targetManagement.createTarget(target); // check initial status assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getUpdateStatus()) @@ -256,8 +257,8 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { // confirm cancellation firstAction = deploymentManagement.findActionWithDetails(firstAction.getId()); firstAction.setStatus(Status.CANCELED); - controllerManagement.addCancelActionStatus( - new ActionStatus(firstAction, Status.CANCELED, System.currentTimeMillis()), firstAction); + controllerManagement + .addCancelActionStatus(new JpaActionStatus(firstAction, Status.CANCELED, System.currentTimeMillis())); assertThat(actionStatusRepository.findAll()).as("wrong size of action status").hasSize(4); assertThat(targetManagement.findTargetByControllerID("4712").getAssignedDistributionSet()) .as("wrong assigned ds").isEqualTo(dsSecond); @@ -273,8 +274,8 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { .as("wrong assigned ds").isEqualTo(dsSecond); // confirm cancellation secondAction.setStatus(Status.CANCELED); - controllerManagement.addCancelActionStatus( - new ActionStatus(secondAction, Status.CANCELED, System.currentTimeMillis()), secondAction); + controllerManagement + .addCancelActionStatus(new JpaActionStatus(secondAction, Status.CANCELED, System.currentTimeMillis())); // cancelled success -> back to dsInstalled assertThat(targetManagement.findTargetByControllerID("4712").getAssignedDistributionSet()) .as("wrong installed ds").isEqualTo(dsInstalled); @@ -286,15 +287,13 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { @Description("Force Quit an Assignment. Expected behaviour is that the action is canceled and is marked as deleted. The assigned Software module") public void forceQuitSetActionToInactive() throws InterruptedException { - Target target = new Target("4712"); - final DistributionSet dsInstalled = TestDataUtil.generateDistributionSet("installed", softwareManagement, - distributionSetManagement, true); - target.getTargetInfo().setInstalledDistributionSet(dsInstalled); - target = targetManagement.createTarget(target); + JpaTarget target = new JpaTarget("4712"); + final DistributionSet dsInstalled = testdataFactory.createDistributionSet("installed", true); + ((JpaTargetInfo) target.getTargetInfo()).setInstalledDistributionSet((JpaDistributionSet) dsInstalled); + target = (JpaTarget) targetManagement.createTarget(target); - final DistributionSet ds = TestDataUtil - .generateDistributionSet("newDS", softwareManagement, distributionSetManagement, true) - .setRequiredMigrationStep(true); + final DistributionSet ds = testdataFactory.createDistributionSet("newDS", true); + ds.setRequiredMigrationStep(true); // verify initial status assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getUpdateStatus()) @@ -306,7 +305,7 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { assertThat(actionRepository.findAll()).as("wrong size of action").hasSize(1); assertThat(actionStatusRepository.findAll()).as("wrong size of action status").hasSize(1); - target = targetManagement.findTargetByControllerID(target.getControllerId()); + target = (JpaTarget) targetManagement.findTargetByControllerID(target.getControllerId()); // force quit assignment deploymentManagement.cancelAction(assigningAction, target); @@ -328,15 +327,13 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { @Description("Force Quit an not canceled Assignment. Expected behaviour is that the action can not be force quit and there is thrown an exception.") public void forceQuitNotAllowedThrowsException() { - Target target = new Target("4712"); - final DistributionSet dsInstalled = TestDataUtil.generateDistributionSet("installed", softwareManagement, - distributionSetManagement, true); - target.getTargetInfo().setInstalledDistributionSet(dsInstalled); + Target target = new JpaTarget("4712"); + final DistributionSet dsInstalled = testdataFactory.createDistributionSet("installed", true); + ((JpaTargetInfo) target.getTargetInfo()).setInstalledDistributionSet((JpaDistributionSet) dsInstalled); target = targetManagement.createTarget(target); - final DistributionSet ds = TestDataUtil - .generateDistributionSet("newDS", softwareManagement, distributionSetManagement, true) - .setRequiredMigrationStep(true); + final DistributionSet ds = testdataFactory.createDistributionSet("newDS", true); + ds.setRequiredMigrationStep(true); // verify initial status assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getUpdateStatus()) @@ -363,7 +360,9 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { .as("wrong update status").isEqualTo(TargetUpdateStatus.PENDING); assertThat(targetManagement.findTargetByControllerID(target.getControllerId()).getAssignedDistributionSet()) .as("wrong assigned ds").isEqualTo(ds); - final Action action = actionRepository.findByTargetAndDistributionSet(pageReq, target, ds).getContent().get(0); + final Action action = actionRepository + .findByTargetAndDistributionSet(pageReq, (JpaTarget) target, (JpaDistributionSet) ds).getContent() + .get(0); assertThat(action).as("action should not be null").isNotNull(); return action; } @@ -384,14 +383,13 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { final String myCtrlIDPref = "myCtrlID"; final Iterable savedNakedTargets = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(10, myCtrlIDPref, "first description")); + .createTargets(testdataFactory.generateTargets(10, myCtrlIDPref, "first description")); final String myDeployedCtrlIDPref = "myDeployedCtrlID"; List savedDeployedTargets = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(20, myDeployedCtrlIDPref, "first description")); + .createTargets(testdataFactory.generateTargets(20, myDeployedCtrlIDPref, "first description")); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet(""); deploymentManagement.assignDistributionSet(ds, savedDeployedTargets); @@ -438,17 +436,17 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { final EventHandlerMock eventHandlerMock = new EventHandlerMock(0); eventBus.register(eventHandlerMock); - final List targets = targetManagement.createTargets(TestDataUtil.generateTargets(10)); + final List targets = testdataFactory.createTargets(10); final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, "")); final SoftwareModule jvm = softwareManagement - .createSoftwareModule(new SoftwareModule(runtimeType, "oracle-jre", "1.7.2", null, "")); + .createSoftwareModule(new JpaSoftwareModule(runtimeType, "oracle-jre", "1.7.2", null, "")); final SoftwareModule os = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "poky", "3.0.2", null, "")); + .createSoftwareModule(new JpaSoftwareModule(osType, "poky", "3.0.2", null, "")); final DistributionSet incomplete = distributionSetManagement.createDistributionSet( - new DistributionSet("incomplete", "v1", "", standardDsType, Lists.newArrayList(ah, jvm))); + new JpaDistributionSet("incomplete", "v1", "", standardDsType, Lists.newArrayList(ah, jvm))); try { deploymentManagement.assignDistributionSet(incomplete, targets); @@ -502,11 +500,11 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { final List deployedTargetIDs = deploymentResult.getDeployedTargetIDs(); final List undeployedTargetIDs = deploymentResult.getUndeployedTargetIDs(); - final List savedNakedTargets = deploymentResult.getUndeployedTargets(); - final List savedDeployedTargets = deploymentResult.getDeployedTargets(); + final Collection savedNakedTargets = (Collection) deploymentResult.getUndeployedTargets(); + final Collection savedDeployedTargets = (Collection) deploymentResult.getDeployedTargets(); // retrieving all Actions created by the assignDistributionSet call - final Page page = actionRepository.findAll(pageReq); + final Page page = actionRepository.findAll(pageReq); // and verify the number assertThat(page.getTotalElements()).as("wrong size of actions") .isEqualTo(noOfDeployedTargets * noOfDistributionSets); @@ -514,10 +512,10 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { // only records retrieved from the DB can be evaluated to be sure that // all fields are // populated; - final Iterable allFoundTargets = targetRepository.findAll(); + final Iterable allFoundTargets = targetRepository.findAll(); - final Iterable deployedTargetsFromDB = targetRepository.findAll(deployedTargetIDs); - final Iterable undeployedTargetsFromDB = targetRepository.findAll(undeployedTargetIDs); + final Iterable deployedTargetsFromDB = targetRepository.findAll(deployedTargetIDs); + final Iterable undeployedTargetsFromDB = targetRepository.findAll(undeployedTargetIDs); // test that number of Targets assertThat(allFoundTargets.spliterator().getExactSizeIfKnown()).as("number of target is wrong") @@ -532,9 +530,9 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { assertThat(allFoundTargets).as("content of founded target is wrong").containsAll(deployedTargetsFromDB) .containsAll(undeployedTargetsFromDB); assertThat(deployedTargetsFromDB).as("content of deployed target is wrong").containsAll(savedDeployedTargets) - .doesNotContain(Iterables.toArray(undeployedTargetsFromDB, Target.class)); + .doesNotContain(Iterables.toArray(undeployedTargetsFromDB, JpaTarget.class)); assertThat(undeployedTargetsFromDB).as("content of undeployed target is wrong").containsAll(savedNakedTargets) - .doesNotContain(Iterables.toArray(deployedTargetsFromDB, Target.class)); + .doesNotContain(Iterables.toArray(deployedTargetsFromDB, JpaTarget.class)); // For each of the 4 targets 1 distribution sets gets assigned eventHandlerMock.getEvents(10, TimeUnit.SECONDS); @@ -556,9 +554,9 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { final DeploymentResult deployResWithDsC = prepareComplexRepo("undep-C-T", 4, "dep-C-T", 6, 1, "dsC"); // keep a reference to the created DistributionSets - final DistributionSet dsA = deployResWithDsA.getDistributionSets().get(0); - final DistributionSet dsB = deployResWithDsB.getDistributionSets().get(0); - final DistributionSet dsC = deployResWithDsC.getDistributionSets().get(0); + final JpaDistributionSet dsA = (JpaDistributionSet) deployResWithDsA.getDistributionSets().get(0); + final JpaDistributionSet dsB = (JpaDistributionSet) deployResWithDsB.getDistributionSets().get(0); + final JpaDistributionSet dsC = (JpaDistributionSet) deployResWithDsC.getDistributionSets().get(0); // retrieving the UpdateActions created by the assignments actionRepository.findByDistributionSet(pageRequest, dsA).getContent().get(0); @@ -649,7 +647,7 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { final DeploymentResult deploymentResult = prepareComplexRepo(undeployedTargetPrefix, noOfUndeployedTargets, deployedTargetPrefix, noOfDeployedTargets, noOfDistributionSets, "myTestDS"); - DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, distributionSetManagement); + DistributionSet dsA = testdataFactory.createDistributionSet(""); distributionSetManagement.deleteDistributionSet(dsA.getId()); dsA = distributionSetManagement.findDistributionSetById(dsA.getId()); @@ -664,10 +662,11 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { } // verify that deleted attribute is used correctly - List allFoundDS = distributionSetManagement.findDistributionSetsAll(pageReq, false, true) - .getContent(); + List allFoundDS = distributionSetManagement + .findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true).getContent(); assertThat(allFoundDS.size()).as("no ds should be founded").isEqualTo(0); - allFoundDS = distributionSetManagement.findDistributionSetsAll(pageRequest, true, true).getContent(); + allFoundDS = distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageRequest, true, true) + .getContent(); assertThat(allFoundDS).as("wrong size of founded ds").hasSize(noOfDistributionSets); for (final DistributionSet ds : deploymentResult.getDistributionSets()) { @@ -681,9 +680,11 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { // has been installed // successfully and no activeAction is referring to created distribution // sets - allFoundDS = distributionSetManagement.findDistributionSetsAll(pageRequest, false, true).getContent(); + allFoundDS = distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageRequest, false, true) + .getContent(); assertThat(allFoundDS.size()).as("no ds should be founded").isEqualTo(0); - allFoundDS = distributionSetManagement.findDistributionSetsAll(pageRequest, true, true).getContent(); + allFoundDS = distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageRequest, true, true) + .getContent(); assertThat(allFoundDS).as("size of founded ds is wrong").hasSize(noOfDistributionSets); } @@ -721,9 +722,9 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { private List sendUpdateActionStatusToTargets(final DistributionSet dsA, final Iterable targs, final Status status, final String... msgs) { - final List result = new ArrayList(); + final List result = new ArrayList<>(); for (final Target t : targs) { - final List findByTarget = actionRepository.findByTarget(t); + final List findByTarget = actionRepository.findByTarget((JpaTarget) t); for (final Action action : findByTarget) { result.add(sendUpdateActionStatusToTarget(status, action, t, msgs)); } @@ -735,14 +736,14 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { final String... msgs) { updActA.setStatus(status); - final ActionStatus statusMessages = new ActionStatus(); + final ActionStatus statusMessages = new JpaActionStatus(); statusMessages.setAction(updActA); statusMessages.setOccurredAt(System.currentTimeMillis()); statusMessages.setStatus(status); for (final String msg : msgs) { statusMessages.addMessage(msg); } - controllerManagament.addUpdateActionStatus(statusMessages, updActA); + controllerManagament.addUpdateActionStatus(statusMessages); return targetManagement.findTargetByControllerID(t.getControllerId()); } @@ -750,14 +751,11 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { @Description("Testing if changing target and the status without refreshing the entities from the DB (e.g. concurrent changes from UI and from controller) works") public void alternatingAssignmentAndAddUpdateActionStatus() { - final DistributionSet dsA = TestDataUtil.generateDistributionSet("a", softwareManagement, - distributionSetManagement); - final DistributionSet dsB = TestDataUtil.generateDistributionSet("b", softwareManagement, - distributionSetManagement); - Target targ = targetManagement - .createTarget(TestDataUtil.buildTargetFixture("target-id-A", "first description")); + final DistributionSet dsA = testdataFactory.createDistributionSet("a"); + final DistributionSet dsB = testdataFactory.createDistributionSet("b"); + Target targ = targetManagement.createTarget(testdataFactory.generateTarget("target-id-A", "first description")); - List targs = new ArrayList(); + List targs = new ArrayList<>(); targs.add(targ); // doing the assignment @@ -782,11 +780,12 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { assertThat(deploymentManagement.findActiveActionsByTarget(targ).get(0).getDistributionSet()) .as("Installed distribution set of action should be null").isNotNull(); - final Page updAct = actionRepository.findByDistributionSet(pageReq, dsA); + final Page updAct = actionRepository.findByDistributionSet(pageReq, (JpaDistributionSet) dsA); final Action action = updAct.getContent().get(0); action.setStatus(Status.FINISHED); - final ActionStatus statusMessage = new ActionStatus(action, Status.FINISHED, System.currentTimeMillis(), ""); - controllerManagament.addUpdateActionStatus(statusMessage, action); + final ActionStatus statusMessage = new JpaActionStatus((JpaAction) action, Status.FINISHED, + System.currentTimeMillis(), ""); + controllerManagament.addUpdateActionStatus(statusMessage); targ = targetManagement.findTargetByControllerID(targ.getControllerId()); @@ -819,11 +818,9 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { @Description("The test verfies that the DS itself is not changed because of an target assignment" + " which is a relationship but not a changed on the entity itself..") public void checkThatDsRevisionsIsNotChangedWithTargetAssignment() { - final DistributionSet dsA = TestDataUtil.generateDistributionSet("a", softwareManagement, - distributionSetManagement); - TestDataUtil.generateDistributionSet("b", softwareManagement, distributionSetManagement); - Target targ = targetManagement - .createTarget(TestDataUtil.buildTargetFixture("target-id-A", "first description")); + final DistributionSet dsA = testdataFactory.createDistributionSet("a"); + testdataFactory.createDistributionSet("b"); + Target targ = targetManagement.createTarget(testdataFactory.generateTarget("target-id-A", "first description")); assertThat(dsA.getOptLockRevision()).as("lock revision is wrong").isEqualTo( distributionSetManagement.findDistributionSetByIdWithDetails(dsA.getId()).getOptLockRevision()); @@ -841,12 +838,12 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { @Description("Tests the switch from a soft to hard update by API") public void forceSoftAction() { // prepare - final Target target = targetManagement.createTarget(new Target("knownControllerId")); - final DistributionSet ds = TestDataUtil.generateDistributionSet("a", softwareManagement, - distributionSetManagement); + final Target target = targetManagement.createTarget(new JpaTarget("knownControllerId")); + final DistributionSet ds = testdataFactory.createDistributionSet("a"); // assign ds to create an action - final DistributionSetAssignmentResult assignDistributionSet = deploymentManagement - .assignDistributionSet(ds.getId(), ActionType.SOFT, Action.NO_FORCE_TIME, target.getControllerId()); + final DistributionSetAssignmentResult assignDistributionSet = deploymentManagement.assignDistributionSet( + ds.getId(), ActionType.SOFT, org.eclipse.hawkbit.repository.model.RepositoryModelConstants.NO_FORCE_TIME, + target.getControllerId()); final Action action = deploymentManagement.findActionWithDetails(assignDistributionSet.getActions().get(0)); // verify preparation Action findAction = deploymentManagement.findAction(action.getId()); @@ -864,12 +861,12 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { @Description("Tests the switch from a hard to hard update by API, e.g. which in fact should not change anything.") public void forceAlreadyForcedActionNothingChanges() { // prepare - final Target target = targetManagement.createTarget(new Target("knownControllerId")); - final DistributionSet ds = TestDataUtil.generateDistributionSet("a", softwareManagement, - distributionSetManagement); + final Target target = targetManagement.createTarget(new JpaTarget("knownControllerId")); + final DistributionSet ds = testdataFactory.createDistributionSet("a"); // assign ds to create an action - final DistributionSetAssignmentResult assignDistributionSet = deploymentManagement - .assignDistributionSet(ds.getId(), ActionType.FORCED, Action.NO_FORCE_TIME, target.getControllerId()); + final DistributionSetAssignmentResult assignDistributionSet = deploymentManagement.assignDistributionSet( + ds.getId(), ActionType.FORCED, org.eclipse.hawkbit.repository.model.RepositoryModelConstants.NO_FORCE_TIME, + target.getControllerId()); final Action action = deploymentManagement.findActionWithDetails(assignDistributionSet.getActions().get(0)); // verify perparation Action findAction = deploymentManagement.findAction(action.getId()); @@ -912,14 +909,14 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { final String deployedTargetPrefix, final int noOfDeployedTargets, final int noOfDistributionSets, final String distributionSetPrefix) { final Iterable nakedTargets = targetManagement.createTargets( - TestDataUtil.buildTargetFixtures(noOfUndeployedTargets, undeployedTargetPrefix, "first description")); + testdataFactory.generateTargets(noOfUndeployedTargets, undeployedTargetPrefix, "first description")); List deployedTargets = targetManagement.createTargets( - TestDataUtil.buildTargetFixtures(noOfDeployedTargets, deployedTargetPrefix, "first description")); + testdataFactory.generateTargets(noOfDeployedTargets, deployedTargetPrefix, "first description")); // creating 10 DistributionSets - final List dsList = TestDataUtil.generateDistributionSets(distributionSetPrefix, - noOfDistributionSets, softwareManagement, distributionSetManagement); + final Collection dsList = testdataFactory.createDistributionSets(distributionSetPrefix, + noOfDistributionSets); String time = String.valueOf(System.currentTimeMillis()); time = time.substring(time.length() - 5); @@ -1048,8 +1045,7 @@ public class DeploymentManagementTest extends AbstractIntegrationTest { public List getEvents(final long timeout, final TimeUnit unit) throws InterruptedException { latch.await(timeout, unit); - final List handledEvents = new LinkedList( - events); + final List handledEvents = new LinkedList<>(events); assertThat(handledEvents).as("Did not receive the expected amount of events (" + expectedNumberOfEvents + ") within timeout. Received events are " + handledEvents).hasSize(expectedNumberOfEvents); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/DistributionSetManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java similarity index 78% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/DistributionSetManagementTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java index db9618425..b7da2ff06 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/DistributionSetManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java @@ -6,33 +6,47 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.fail; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.WithUser; -import org.eclipse.hawkbit.repository.DistributionSetFilter.DistributionSetFilterBuilder; +import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityLockedException; import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.fest.assertions.core.Condition; import org.junit.Test; import org.springframework.data.domain.Page; @@ -50,13 +64,13 @@ import ru.yandex.qatools.allure.annotations.Stories; */ @Features("Component Tests - Repository") @Stories("DistributionSet Management") -public class DistributionSetManagementTest extends AbstractIntegrationTest { +public class DistributionSetManagementTest extends AbstractJpaIntegrationTest { @Test @Description("Tests the successfull module update of unused distribution set type which is in fact allowed.") public void updateUnassignedDistributionSetTypeModules() { DistributionSetType updatableType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("updatableType", "to be deleted", "")); + .createDistributionSetType(new JpaDistributionSetType("updatableType", "to be deleted", "")); assertThat(distributionSetManagement.findDistributionSetTypeByKey("updatableType").getMandatoryModuleTypes()) .isEmpty(); @@ -83,11 +97,11 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Description("Tests the successfull update of used distribution set type meta data hich is in fact allowed.") public void updateAssignedDistributionSetTypeMetaData() { final DistributionSetType nonUpdatableType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("updatableType", "to be deletd", "")); + .createDistributionSetType(new JpaDistributionSetType("updatableType", "to be deletd", "")); assertThat(distributionSetManagement.findDistributionSetTypeByKey("updatableType").getMandatoryModuleTypes()) .isEmpty(); distributionSetManagement - .createDistributionSet(new DistributionSet("newtypesoft", "1", "", nonUpdatableType, null)); + .createDistributionSet(new JpaDistributionSet("newtypesoft", "1", "", nonUpdatableType, null)); nonUpdatableType.setDescription("a new description"); nonUpdatableType.setColour("test123"); @@ -104,11 +118,11 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Description("Tests the unsuccessfull update of used distribution set type (module addition).") public void addModuleToAssignedDistributionSetTypeFails() { final DistributionSetType nonUpdatableType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("updatableType", "to be deletd", "")); + .createDistributionSetType(new JpaDistributionSetType("updatableType", "to be deletd", "")); assertThat(distributionSetManagement.findDistributionSetTypeByKey("updatableType").getMandatoryModuleTypes()) .isEmpty(); distributionSetManagement - .createDistributionSet(new DistributionSet("newtypesoft", "1", "", nonUpdatableType, null)); + .createDistributionSet(new JpaDistributionSet("newtypesoft", "1", "", nonUpdatableType, null)); nonUpdatableType.addMandatoryModuleType(osType); @@ -125,14 +139,14 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Description("Tests the unsuccessfull update of used distribution set type (module removal).") public void removeModuleToAssignedDistributionSetTypeFails() { DistributionSetType nonUpdatableType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("updatableType", "to be deletd", "")); + .createDistributionSetType(new JpaDistributionSetType("updatableType", "to be deletd", "")); assertThat(distributionSetManagement.findDistributionSetTypeByKey("updatableType").getMandatoryModuleTypes()) .isEmpty(); nonUpdatableType.addMandatoryModuleType(osType); nonUpdatableType = distributionSetManagement.updateDistributionSetType(nonUpdatableType); distributionSetManagement - .createDistributionSet(new DistributionSet("newtypesoft", "1", "", nonUpdatableType, null)); + .createDistributionSet(new JpaDistributionSet("newtypesoft", "1", "", nonUpdatableType, null)); nonUpdatableType.removeModuleType(osType.getId()); try { @@ -146,8 +160,8 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Test @Description("Tests the successfull deletion of unused (hard delete) distribution set types.") public void deleteUnassignedDistributionSetType() { - final DistributionSetType hardDelete = distributionSetManagement - .createDistributionSetType(new DistributionSetType("deleted", "to be deleted", "")); + final JpaDistributionSetType hardDelete = (JpaDistributionSetType) distributionSetManagement + .createDistributionSetType(new JpaDistributionSetType("deleted", "to be deleted", "")); assertThat(distributionSetTypeRepository.findAll()).contains(hardDelete); distributionSetManagement.deleteDistributionSetType(hardDelete); @@ -158,11 +172,12 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Test @Description("Tests the successfull deletion of used (soft delete) distribution set types.") public void deleteAssignedDistributionSetType() { - final DistributionSetType softDelete = distributionSetManagement - .createDistributionSetType(new DistributionSetType("softdeleted", "to be deletd", "")); + final JpaDistributionSetType softDelete = (JpaDistributionSetType) distributionSetManagement + .createDistributionSetType(new JpaDistributionSetType("softdeleted", "to be deletd", "")); assertThat(distributionSetTypeRepository.findAll()).contains(softDelete); - distributionSetManagement.createDistributionSet(new DistributionSet("newtypesoft", "1", "", softDelete, null)); + distributionSetManagement + .createDistributionSet(new JpaDistributionSet("newtypesoft", "1", "", softDelete, null)); distributionSetManagement.deleteDistributionSetType(softDelete); assertThat(distributionSetManagement.findDistributionSetTypeByKey("softdeleted").isDeleted()).isEqualTo(true); @@ -171,10 +186,10 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Test @Description("Ensures that it is not possible to create a DS that already exists (unique constraint is on name,version for DS).") public void createDuplicateDistributionSetsFailsWithException() { - TestDataUtil.generateDistributionSet("a", softwareManagement, distributionSetManagement); + testdataFactory.createDistributionSet("a"); try { - TestDataUtil.generateDistributionSet("a", softwareManagement, distributionSetManagement); + testdataFactory.createDistributionSet("a"); fail("Should not have worked as DS with same UK already exists."); } catch (final EntityAlreadyExistsException e) { @@ -185,7 +200,7 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Description("Verfies that a DS is of default type if not specified explicitly at creation time.") public void createDistributionSetWithImplicitType() { final DistributionSet set = distributionSetManagement - .createDistributionSet(new DistributionSet("newtypesoft", "1", "", null, null)); + .createDistributionSet(new JpaDistributionSet("newtypesoft", "1", "", null, null)); assertThat(set.getType()).as("Type should be equal to default type of tenant") .isEqualTo(systemManagement.getTenantMetadata().getDefaultDsType()); @@ -198,7 +213,7 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { List sets = new ArrayList<>(); for (int i = 0; i < 10; i++) { - sets.add(new DistributionSet("another DS" + i, "X" + i, "", null, null)); + sets.add(new JpaDistributionSet("another DS" + i, "X" + i, "", null, null)); } sets = distributionSetManagement.createDistributionSets(sets); @@ -216,7 +231,7 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Description("Verfies that a DS entity cannot be used for creation.") public void createDistributionSetFailsOnExistingEntity() { final DistributionSet set = distributionSetManagement - .createDistributionSet(new DistributionSet("newtypesoft", "1", "", null, null)); + .createDistributionSet(new JpaDistributionSet("newtypesoft", "1", "", null, null)); try { distributionSetManagement.createDistributionSet(set); @@ -232,11 +247,10 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { final String knownKey = "dsMetaKnownKey"; final String knownValue = "dsMetaKnownValue"; - final DistributionSet ds = TestDataUtil.generateDistributionSet("testDs", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet("testDs"); - final DistributionSetMetadata metadata = new DistributionSetMetadata(knownKey, ds, knownValue); - final DistributionSetMetadata createdMetadata = distributionSetManagement + final DistributionSetMetadata metadata = new JpaDistributionSetMetadata(knownKey, ds, knownValue); + final JpaDistributionSetMetadata createdMetadata = (JpaDistributionSetMetadata) distributionSetManagement .createDistributionSetMetadata(metadata); assertThat(createdMetadata).isNotNull(); @@ -249,14 +263,13 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Description("Ensures that updates concerning the internal software structure of a DS are not possible if the DS is already assigned.") public void updateDistributionSetForbiddedWithIllegalUpdate() { // prepare data - Target target = new Target("4711"); + Target target = new JpaTarget("4711"); target = targetManagement.createTarget(target); - SoftwareModule ah2 = new SoftwareModule(appType, "agent-hub2", "1.0.5", null, ""); - SoftwareModule os2 = new SoftwareModule(osType, "poky2", "3.0.3", null, ""); + SoftwareModule ah2 = new JpaSoftwareModule(appType, "agent-hub2", "1.0.5", null, ""); + SoftwareModule os2 = new JpaSoftwareModule(osType, "poky2", "3.0.3", null, ""); - DistributionSet ds = TestDataUtil.generateDistributionSet("ds-1", softwareManagement, - distributionSetManagement); + DistributionSet ds = testdataFactory.createDistributionSet("ds-1"); ah2 = softwareManagement.createSoftwareModule(ah2); os2 = softwareManagement.createSoftwareModule(os2); @@ -303,8 +316,8 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Test @Description("Ensures that it is not possible to add a software module to a set that has no type defined.") public void updateDistributionSetModuleWithUndefinedTypeFails() { - final DistributionSet testSet = new DistributionSet(); - final SoftwareModule module = new SoftwareModule(appType, "agent-hub2", "1.0.5", null, ""); + final DistributionSet testSet = new JpaDistributionSet(); + final SoftwareModule module = new JpaSoftwareModule(appType, "agent-hub2", "1.0.5", null, ""); // update data try { @@ -318,9 +331,9 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Test @Description("Ensures that it is not possible to add a software module that is not defined of the DS's type.") public void updateDistributionSetUnsupportedModuleFails() { - final DistributionSet set = new DistributionSet("agent-hub2", "1.0.5", "desc", - new DistributionSetType("test", "test", "test").addMandatoryModuleType(osType), null); - final SoftwareModule module = new SoftwareModule(appType, "agent-hub2", "1.0.5", null, ""); + final DistributionSet set = new JpaDistributionSet("agent-hub2", "1.0.5", "desc", + new JpaDistributionSetType("test", "test", "test").addMandatoryModuleType(osType), null); + final SoftwareModule module = new JpaSoftwareModule(appType, "agent-hub2", "1.0.5", null, ""); // update data try { @@ -335,13 +348,13 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Description("Legal updates of a DS, e.g. name or description and module addition, removal while still unassigned.") public void updateDistributionSet() { // prepare data - Target target = new Target("4711"); + Target target = new JpaTarget("4711"); target = targetManagement.createTarget(target); - SoftwareModule os2 = new SoftwareModule(osType, "poky2", "3.0.3", null, ""); - final SoftwareModule app2 = new SoftwareModule(appType, "app2", "3.0.3", null, ""); + SoftwareModule os2 = new JpaSoftwareModule(osType, "poky2", "3.0.3", null, ""); + final SoftwareModule app2 = new JpaSoftwareModule(appType, "app2", "3.0.3", null, ""); - DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, distributionSetManagement); + DistributionSet ds = testdataFactory.createDistributionSet(""); os2 = softwareManagement.createSoftwareModule(os2); @@ -380,14 +393,13 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { final String knownUpdateValue = "myNewUpdatedValue"; // create a DS - final DistributionSet ds = TestDataUtil.generateDistributionSet("testDs", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet("testDs"); // initial opt lock revision must be zero assertThat(ds.getOptLockRevision()).isEqualTo(1L); // create an DS meta data entry final DistributionSetMetadata dsMetadata = distributionSetManagement - .createDistributionSetMetadata(new DistributionSetMetadata(knownKey, ds, knownValue)); + .createDistributionSetMetadata(new JpaDistributionSetMetadata(knownKey, ds, knownValue)); DistributionSet changedLockRevisionDS = distributionSetManagement.findDistributionSetById(ds.getId()); assertThat(changedLockRevisionDS.getOptLockRevision()).isEqualTo(2L); @@ -395,12 +407,13 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { // modifying the meta data value dsMetadata.setValue(knownUpdateValue); dsMetadata.setKey(knownKey); - dsMetadata.setDistributionSet(changedLockRevisionDS); + ((JpaDistributionSetMetadata) dsMetadata).setDistributionSet(changedLockRevisionDS); Thread.sleep(100); // update the DS metadata - final DistributionSetMetadata updated = distributionSetManagement.updateDistributionSetMetadata(dsMetadata); + final JpaDistributionSetMetadata updated = (JpaDistributionSetMetadata) distributionSetManagement + .updateDistributionSetMetadata(dsMetadata); // we are updating the sw meta data so also modifying the base software // module so opt lock // revision must be three @@ -419,11 +432,10 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Description("Tests that a DS queue is possible where the result is ordered by the target assignment, i.e. assigned first in the list.") public void findDistributionSetsAllOrderedByLinkTarget() { - final List buildDistributionSets = TestDataUtil.generateDistributionSets("dsOrder", 10, - softwareManagement, distributionSetManagement); + final List buildDistributionSets = testdataFactory.createDistributionSets("dsOrder", 10); final List buildTargetFixtures = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(5, "tOrder", "someDesc")); + .createTargets(testdataFactory.generateTargets(5, "tOrder", "someDesc")); final Iterator dsIterator = buildDistributionSets.iterator(); final Iterator tIterator = buildTargetFixtures.iterator(); @@ -466,32 +478,28 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Description("searches for distribution sets based on the various filter options, e.g. name, version, desc., tags.") public void searchDistributionSetsOnFilters() { DistributionSetTag dsTagA = tagManagement - .createDistributionSetTag(new DistributionSetTag("DistributionSetTag-A")); + .createDistributionSetTag(new JpaDistributionSetTag("DistributionSetTag-A")); final DistributionSetTag dsTagB = tagManagement - .createDistributionSetTag(new DistributionSetTag("DistributionSetTag-B")); + .createDistributionSetTag(new JpaDistributionSetTag("DistributionSetTag-B")); final DistributionSetTag dsTagC = tagManagement - .createDistributionSetTag(new DistributionSetTag("DistributionSetTag-C")); + .createDistributionSetTag(new JpaDistributionSetTag("DistributionSetTag-C")); final DistributionSetTag dsTagD = tagManagement - .createDistributionSetTag(new DistributionSetTag("DistributionSetTag-D")); + .createDistributionSetTag(new JpaDistributionSetTag("DistributionSetTag-D")); - List ds100Group1 = TestDataUtil.generateDistributionSets("", 100, softwareManagement, - distributionSetManagement); - List ds100Group2 = TestDataUtil.generateDistributionSets("test2", 100, softwareManagement, - distributionSetManagement); - DistributionSet dsDeleted = TestDataUtil.generateDistributionSet("deleted", softwareManagement, - distributionSetManagement); + Collection ds100Group1 = testdataFactory.createDistributionSets("", 100); + Collection ds100Group2 = testdataFactory.createDistributionSets("test2", 100); + DistributionSet dsDeleted = testdataFactory.createDistributionSet("deleted"); final DistributionSet dsInComplete = distributionSetManagement - .createDistributionSet(new DistributionSet("notcomplete", "1", "", standardDsType, null)); + .createDistributionSet(new JpaDistributionSet("notcomplete", "1", "", standardDsType, null)); - final DistributionSetType newType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("foo", "bar", "test").addMandatoryModuleType(osType) + final DistributionSetType newType = distributionSetManagement.createDistributionSetType( + new JpaDistributionSetType("foo", "bar", "test").addMandatoryModuleType(osType) .addOptionalModuleType(appType).addOptionalModuleType(runtimeType)); final DistributionSet dsNewType = distributionSetManagement - .createDistributionSet(new DistributionSet("newtype", "1", "", newType, dsDeleted.getModules())); + .createDistributionSet(new JpaDistributionSet("newtype", "1", "", newType, dsDeleted.getModules())); - deploymentManagement.assignDistributionSet(dsDeleted, - targetManagement.createTargets(Lists.newArrayList(TestDataUtil.generateTargets(5)))); + deploymentManagement.assignDistributionSet(dsDeleted, Lists.newArrayList(testdataFactory.createTargets(5))); distributionSetManagement.deleteDistributionSet(dsDeleted); dsDeleted = distributionSetManagement.findDistributionSetById(dsDeleted.getId()); @@ -705,7 +713,7 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { final Status status, final String... msgs) { final List result = new ArrayList<>(); for (final Target t : targs) { - final List findByTarget = actionRepository.findByTarget(t); + final List findByTarget = actionRepository.findByTarget((JpaTarget) t); for (final Action action : findByTarget) { result.add(sendUpdateActionStatusToTarget(status, action, t, msgs)); } @@ -716,18 +724,17 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { @Test @Description("Simple DS load without the related data that should be loaded lazy.") public void findDistributionSetsWithoutLazy() { - TestDataUtil.generateDistributionSets(20, softwareManagement, distributionSetManagement); + testdataFactory.createDistributionSets(20); - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, false, true)).hasSize(20); + assertThat(distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, true)) + .hasSize(20); } @Test @Description("Deltes a DS that is no in use. Expected behaviour is a hard delete on the database.") public void deleteUnassignedDistributionSet() { - DistributionSet ds1 = TestDataUtil.generateDistributionSet("ds-1", softwareManagement, - distributionSetManagement); - DistributionSet ds2 = TestDataUtil.generateDistributionSet("ds-2", softwareManagement, - distributionSetManagement); + DistributionSet ds1 = testdataFactory.createDistributionSet("ds-1"); + DistributionSet ds2 = testdataFactory.createDistributionSet("ds-2"); ds1 = distributionSetManagement.findDistributionSetByNameAndVersion(ds1.getName(), ds1.getVersion()); ds2 = distributionSetManagement.findDistributionSetByNameAndVersion(ds2.getName(), ds2.getVersion()); @@ -737,30 +744,29 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { distributionSetManagement.deleteDistributionSet(ds1.getId()); // not assigned so not marked as deleted but fully deleted assertThat(distributionSetRepository.findAll()).hasSize(1); - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, Boolean.FALSE, Boolean.TRUE) - .getTotalElements()).isEqualTo(1); + assertThat(distributionSetManagement + .findDistributionSetsByDeletedAndOrCompleted(pageReq, Boolean.FALSE, Boolean.TRUE).getTotalElements()) + .isEqualTo(1); } @Test @Description("Queries and loads the metadata related to a given software module.") public void findAllDistributionSetMetadataByDsId() { // create a DS - DistributionSet ds1 = TestDataUtil.generateDistributionSet("testDs1", softwareManagement, - distributionSetManagement); - DistributionSet ds2 = TestDataUtil.generateDistributionSet("testDs2", softwareManagement, - distributionSetManagement); + DistributionSet ds1 = testdataFactory.createDistributionSet("testDs1"); + DistributionSet ds2 = testdataFactory.createDistributionSet("testDs2"); for (int index = 0; index < 10; index++) { ds1 = distributionSetManagement - .createDistributionSetMetadata(new DistributionSetMetadata("key" + index, ds1, "value" + index)) + .createDistributionSetMetadata(new JpaDistributionSetMetadata("key" + index, ds1, "value" + index)) .getDistributionSet(); } for (int index = 0; index < 20; index++) { ds2 = distributionSetManagement - .createDistributionSetMetadata(new DistributionSetMetadata("key" + index, ds2, "value" + index)) + .createDistributionSetMetadata(new JpaDistributionSetMetadata("key" + index, ds2, "value" + index)) .getDistributionSet(); } @@ -778,50 +784,67 @@ public class DistributionSetManagementTest extends AbstractIntegrationTest { } @Test - @Description("Deltes a DS that is no in use. Expected behaviour is a soft delete on the database, i.e. only marked as " - + "deleted, kept eas refernce and unavailable for future use..") + @Description("Deletes a DS that is in use by either target assignment or rollout. Expected behaviour is a soft delete on the database, i.e. only marked as " + + "deleted, kept as reference but unavailable for future use..") public void deleteAssignedDistributionSet() { - DistributionSet ds1 = TestDataUtil.generateDistributionSet("ds-1", softwareManagement, - distributionSetManagement); - DistributionSet ds2 = TestDataUtil.generateDistributionSet("ds-2", softwareManagement, - distributionSetManagement); - DistributionSet dsAssigned = TestDataUtil.generateDistributionSet("ds-3", softwareManagement, - distributionSetManagement); + DistributionSet ds1 = testdataFactory.createDistributionSet("ds-1"); + DistributionSet ds2 = testdataFactory.createDistributionSet("ds-2"); + DistributionSet dsToTargetAssigned = testdataFactory.createDistributionSet("ds-3"); + final DistributionSet dsToRolloutAssigned = testdataFactory.createDistributionSet("ds-4"); ds1 = distributionSetManagement.findDistributionSetByNameAndVersion(ds1.getName(), ds1.getVersion()); ds2 = distributionSetManagement.findDistributionSetByNameAndVersion(ds2.getName(), ds2.getVersion()); // create assigned DS - dsAssigned = distributionSetManagement.findDistributionSetByNameAndVersion(dsAssigned.getName(), - dsAssigned.getVersion()); - final Target target = new Target("4712"); + dsToTargetAssigned = distributionSetManagement.findDistributionSetByNameAndVersion(dsToTargetAssigned.getName(), + dsToTargetAssigned.getVersion()); + final Target target = new JpaTarget("4712"); final Target savedTarget = targetManagement.createTarget(target); final List toAssign = new ArrayList<>(); toAssign.add(savedTarget); - deploymentManagement.assignDistributionSet(dsAssigned, toAssign); + deploymentManagement.assignDistributionSet(dsToTargetAssigned, toAssign); - // delete a ds - assertThat(distributionSetRepository.findAll()).hasSize(3); - distributionSetManagement.deleteDistributionSet(dsAssigned.getId()); + // create assigned rollout + createRolloutByVariables("test", "test", 5, "name==*", dsToRolloutAssigned, "50", "5"); + + // delete assigned ds + assertThat(distributionSetRepository.findAll()).hasSize(4); + distributionSetManagement.deleteDistributionSet(dsToTargetAssigned.getId(), dsToRolloutAssigned.getId()); // not assigned so not marked as deleted - assertThat(distributionSetRepository.findAll()).hasSize(3); - assertThat(distributionSetManagement.findDistributionSetsAll(pageReq, Boolean.FALSE, Boolean.TRUE) - .getTotalElements()).isEqualTo(2); + assertThat(distributionSetRepository.findAll()).hasSize(4); + assertThat(distributionSetManagement + .findDistributionSetsByDeletedAndOrCompleted(pageReq, Boolean.FALSE, Boolean.TRUE).getTotalElements()) + .isEqualTo(2); + } + + private Rollout createRolloutByVariables(final String rolloutName, final String rolloutDescription, + final int groupSize, final String filterQuery, final DistributionSet distributionSet, + final String successCondition, final String errorCondition) { + final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder() + .successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition) + .errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition) + .errorAction(RolloutGroupErrorAction.PAUSE, null).build(); + final Rollout rolloutToCreate = new JpaRollout(); + rolloutToCreate.setName(rolloutName); + rolloutToCreate.setDescription(rolloutDescription); + rolloutToCreate.setTargetFilterQuery(filterQuery); + rolloutToCreate.setDistributionSet(distributionSet); + return rolloutManagement.createRollout(rolloutToCreate, groupSize, conditions); } private Target sendUpdateActionStatusToTarget(final Status status, final Action updActA, final Target t, final String... msgs) { updActA.setStatus(status); - final ActionStatus statusMessages = new ActionStatus(); + final ActionStatus statusMessages = new JpaActionStatus(); statusMessages.setAction(updActA); statusMessages.setOccurredAt(System.currentTimeMillis()); statusMessages.setStatus(status); for (final String msg : msgs) { statusMessages.addMessage(msg); } - controllerManagament.addUpdateActionStatus(statusMessages, updActA); + controllerManagament.addUpdateActionStatus(statusMessages); return targetManagement.findTargetByControllerID(t.getControllerId()); } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/MethodSecurityUtil.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/MethodSecurityUtil.java similarity index 98% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/MethodSecurityUtil.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/MethodSecurityUtil.java index 6633a27e5..032289e87 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/MethodSecurityUtil.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/MethodSecurityUtil.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.Assertions.assertThat; diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/RandomGeneratedInputStream.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RandomGeneratedInputStream.java similarity index 96% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/RandomGeneratedInputStream.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RandomGeneratedInputStream.java index bd5be54f5..a7a1c0956 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/RandomGeneratedInputStream.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RandomGeneratedInputStream.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.jpa; import java.io.IOException; import java.io.InputStream; diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ReportManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ReportManagementTest.java similarity index 87% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ReportManagementTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ReportManagementTest.java index 0184a9d26..ca82924a8 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ReportManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ReportManagementTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.api.Assertions.fail; @@ -20,23 +20,26 @@ import java.util.Calendar; import java.util.List; import java.util.stream.Collectors; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.WithSpringAuthorityRule; -import org.eclipse.hawkbit.WithUser; -import org.eclipse.hawkbit.report.model.DataReportSeries; -import org.eclipse.hawkbit.report.model.DataReportSeriesItem; -import org.eclipse.hawkbit.report.model.InnerOuterDataReportSeries; -import org.eclipse.hawkbit.report.model.SeriesTime; +import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult; +import org.eclipse.hawkbit.repository.ReportManagement; import org.eclipse.hawkbit.repository.ReportManagement.DateTypes; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.repository.report.model.DataReportSeries; +import org.eclipse.hawkbit.repository.report.model.DataReportSeriesItem; +import org.eclipse.hawkbit.repository.report.model.InnerOuterDataReportSeries; +import org.eclipse.hawkbit.repository.report.model.SeriesTime; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; +import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.After; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -54,7 +57,7 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("Report Management") -public class ReportManagementTest extends AbstractIntegrationTest { +public class ReportManagementTest extends AbstractJpaIntegrationTest { @Autowired private ReportManagement reportManagement; @@ -83,7 +86,7 @@ public class ReportManagementTest extends AbstractIntegrationTest { for (int month = 0; month < maxMonthBackAmountCreateTargets; month++) { dynamicDateTimeProvider.nowMinusMonths(month); - targetManagement.createTarget(new Target("t" + month)); + targetManagement.createTarget(new JpaTarget("t" + month)); } final LocalDateTime to = LocalDateTime.now(); @@ -105,7 +108,7 @@ public class ReportManagementTest extends AbstractIntegrationTest { // check cache evict for (int month = 0; month < maxMonthBackAmountCreateTargets; month++) { dynamicDateTimeProvider.nowMinusMonths(month); - targetManagement.createTarget(new Target("t2" + month)); + targetManagement.createTarget(new JpaTarget("t2" + month)); } targetsCreatedOverPeriod = reportManagement.targetsCreatedOverPeriod(DateTypes.perMonth(), from, to); for (final DataReportSeriesItem reportItem : targetsCreatedOverPeriod.getData()) { @@ -127,15 +130,14 @@ public class ReportManagementTest extends AbstractIntegrationTest { final LocalDateTime to = LocalDateTime.now(); final LocalDateTime from = to.minusMonths(maxMonthBackAmountReportTargets); - final DistributionSet distributionSet = TestDataUtil.generateDistributionSet("ds", softwareManagement, - distributionSetManagement); + final DistributionSet distributionSet = testdataFactory.createDistributionSet("ds"); final DynamicDateTimeProvider dynamicDateTimeProvider = new DynamicDateTimeProvider(); auditingHandler.setDateTimeProvider(dynamicDateTimeProvider); for (int month = 0; month < maxMonthBackAmountCreateTargets; month++) { dynamicDateTimeProvider.nowMinusMonths(month); - final Target createTarget = targetManagement.createTarget(new Target("t" + month)); + final Target createTarget = targetManagement.createTarget(new JpaTarget("t" + month)); final DistributionSetAssignmentResult result = deploymentManagement.assignDistributionSet(distributionSet, Lists.newArrayList(createTarget)); controllerManagament.registerRetrieved( @@ -157,7 +159,7 @@ public class ReportManagementTest extends AbstractIntegrationTest { // check cache evict for (int month = 0; month < maxMonthBackAmountCreateTargets; month++) { dynamicDateTimeProvider.nowMinusMonths(month); - final Target createTarget = targetManagement.createTarget(new Target("t2" + month)); + final Target createTarget = targetManagement.createTarget(new JpaTarget("t2" + month)); final DistributionSetAssignmentResult result = deploymentManagement.assignDistributionSet(distributionSet, Lists.newArrayList(createTarget)); controllerManagament.registerRetrieved( @@ -174,27 +176,24 @@ public class ReportManagementTest extends AbstractIntegrationTest { @Test @Description("Tests correct statistics calculation including a correct cache evict.") public void distributionUsageInstalled() { - final Target knownTarget1 = targetManagement.createTarget(new Target("t1")); - final Target knownTarget2 = targetManagement.createTarget(new Target("t2")); - final Target knownTarget3 = targetManagement.createTarget(new Target("t3")); - final Target knownTarget4 = targetManagement.createTarget(new Target("t4")); - final Target knownTarget5 = targetManagement.createTarget(new Target("t5")); + final Target knownTarget1 = targetManagement.createTarget(new JpaTarget("t1")); + final Target knownTarget2 = targetManagement.createTarget(new JpaTarget("t2")); + final Target knownTarget3 = targetManagement.createTarget(new JpaTarget("t3")); + final Target knownTarget4 = targetManagement.createTarget(new JpaTarget("t4")); + final Target knownTarget5 = targetManagement.createTarget(new JpaTarget("t5")); - final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); - final SoftwareModule jvm = softwareManagement - .createSoftwareModule(new SoftwareModule(runtimeType, "oracle-jre", "1.7.2", null, "")); - final SoftwareModule os = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "poky", "3.0.2", null, "")); + final SoftwareModule ah = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_APP); + final SoftwareModule jvm = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_RT); + final SoftwareModule os = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_OS); - final DistributionSet distributionSet1 = distributionSetManagement - .createDistributionSet(TestDataUtil.buildDistributionSet("ds1", "0.0.0", standardDsType, os, jvm, ah)); - final DistributionSet distributionSet11 = distributionSetManagement - .createDistributionSet(TestDataUtil.buildDistributionSet("ds1", "0.0.1", standardDsType, os, jvm, ah)); - final DistributionSet distributionSet2 = distributionSetManagement - .createDistributionSet(TestDataUtil.buildDistributionSet("ds2", "0.0.2", standardDsType, os, jvm, ah)); - final DistributionSet distributionSet3 = distributionSetManagement - .createDistributionSet(TestDataUtil.buildDistributionSet("ds3", "0.0.3", standardDsType, os, jvm, ah)); + final DistributionSet distributionSet1 = distributionSetManagement.createDistributionSet(testdataFactory + .generateDistributionSet("ds1", "0.0.0", standardDsType, Lists.newArrayList(os, jvm, ah))); + final DistributionSet distributionSet11 = distributionSetManagement.createDistributionSet(testdataFactory + .generateDistributionSet("ds1", "0.0.1", standardDsType, Lists.newArrayList(os, jvm, ah))); + final DistributionSet distributionSet2 = distributionSetManagement.createDistributionSet(testdataFactory + .generateDistributionSet("ds2", "0.0.2", standardDsType, Lists.newArrayList(os, jvm, ah))); + final DistributionSet distributionSet3 = distributionSetManagement.createDistributionSet(testdataFactory + .generateDistributionSet("ds3", "0.0.3", standardDsType, Lists.newArrayList(os, jvm, ah))); // ds1(0.0.0)=[target1,target2], ds1(0.0.1)=[target3] deploymentManagement.assignDistributionSet(distributionSet1.getId(), knownTarget1.getControllerId()); @@ -250,7 +249,7 @@ public class ReportManagementTest extends AbstractIntegrationTest { } // Test cache evict - final Target knownTarget6 = targetManagement.createTarget(new Target("t6")); + final Target knownTarget6 = targetManagement.createTarget(new JpaTarget("t6")); deploymentManagement.assignDistributionSet(distributionSet1.getId(), knownTarget6.getControllerId()); sendUpdateActionStatusToTargets(distributionSet1, Lists.newArrayList(knownTarget6), Status.FINISHED, "some message"); @@ -349,26 +348,23 @@ public class ReportManagementTest extends AbstractIntegrationTest { @Description("Tests correct statistics calculation including a correct cache evict.") public void topXDistributionUsage() { - final Target knownTarget1 = targetManagement.createTarget(new Target("t1")); - final Target knownTarget2 = targetManagement.createTarget(new Target("t2")); - final Target knownTarget3 = targetManagement.createTarget(new Target("t3")); - final Target knownTarget4 = targetManagement.createTarget(new Target("t4")); + final Target knownTarget1 = targetManagement.createTarget(new JpaTarget("t1")); + final Target knownTarget2 = targetManagement.createTarget(new JpaTarget("t2")); + final Target knownTarget3 = targetManagement.createTarget(new JpaTarget("t3")); + final Target knownTarget4 = targetManagement.createTarget(new JpaTarget("t4")); - final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); - final SoftwareModule jvm = softwareManagement - .createSoftwareModule(new SoftwareModule(runtimeType, "oracle-jre", "1.7.2", null, "")); - final SoftwareModule os = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "poky", "3.0.2", null, "")); + final SoftwareModule ah = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_APP); + final SoftwareModule jvm = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_RT); + final SoftwareModule os = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_OS); - final DistributionSet distributionSet1 = distributionSetManagement - .createDistributionSet(TestDataUtil.buildDistributionSet("ds1", "0.0.0", standardDsType, os, jvm, ah)); - final DistributionSet distributionSet11 = distributionSetManagement - .createDistributionSet(TestDataUtil.buildDistributionSet("ds1", "0.0.1", standardDsType, os, jvm, ah)); - final DistributionSet distributionSet2 = distributionSetManagement - .createDistributionSet(TestDataUtil.buildDistributionSet("ds2", "0.0.2", standardDsType, os, jvm, ah)); - final DistributionSet distributionSet3 = distributionSetManagement - .createDistributionSet(TestDataUtil.buildDistributionSet("ds3", "0.0.3", standardDsType, os, jvm, ah)); + final DistributionSet distributionSet1 = distributionSetManagement.createDistributionSet(testdataFactory + .generateDistributionSet("ds1", "0.0.0", standardDsType, Lists.newArrayList(os, jvm, ah))); + final DistributionSet distributionSet11 = distributionSetManagement.createDistributionSet(testdataFactory + .generateDistributionSet("ds1", "0.0.1", standardDsType, Lists.newArrayList(os, jvm, ah))); + final DistributionSet distributionSet2 = distributionSetManagement.createDistributionSet(testdataFactory + .generateDistributionSet("ds2", "0.0.2", standardDsType, Lists.newArrayList(os, jvm, ah))); + final DistributionSet distributionSet3 = distributionSetManagement.createDistributionSet(testdataFactory + .generateDistributionSet("ds3", "0.0.3", standardDsType, Lists.newArrayList(os, jvm, ah))); // ds1(0.0.0)=[target1,target2], ds1(0.0.1)=[target3] deploymentManagement.assignDistributionSet(distributionSet1.getId(), knownTarget1.getControllerId()); @@ -419,7 +415,7 @@ public class ReportManagementTest extends AbstractIntegrationTest { } // test cache evict - final Target knownTarget5 = targetManagement.createTarget(new Target("t5")); + final Target knownTarget5 = targetManagement.createTarget(new JpaTarget("t5")); deploymentManagement.assignDistributionSet(distributionSet1.getId(), knownTarget5.getControllerId()); distributionUsage = reportManagement.distributionUsageAssigned(100); for (final InnerOuterDataReportSeries innerOuterDataReportSeries : distributionUsage) { @@ -490,7 +486,7 @@ public class ReportManagementTest extends AbstractIntegrationTest { // create targets for another tenant securityRule.runAs(WithSpringAuthorityRule.withUserAndTenant("user", "anotherTenant"), () -> { for (int index = 0; index < targetCreateAmount; index++) { - targetManagement.createTarget(new Target("t" + index)); + targetManagement.createTarget(new JpaTarget("t" + index)); } return null; }); @@ -513,10 +509,10 @@ public class ReportManagementTest extends AbstractIntegrationTest { private void createTargets(final String prefix, final int amount, final LocalDateTime lastTargetQuery) { for (int index = 0; index < amount; index++) { - final Target target = new Target(prefix + index); - final Target createTarget = targetManagement.createTarget(target); + final Target target = new JpaTarget(prefix + index); + final JpaTarget createTarget = (JpaTarget) targetManagement.createTarget(target); if (lastTargetQuery != null) { - final TargetInfo targetInfo = createTarget.getTargetInfo(); + final JpaTargetInfo targetInfo = (JpaTargetInfo) createTarget.getTargetInfo(); targetInfo.setNew(false); targetInfo .setLastTargetQuery(lastTargetQuery.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); @@ -527,9 +523,9 @@ public class ReportManagementTest extends AbstractIntegrationTest { private void createTargetsWithStatus(final String prefix, final long amount, final TargetUpdateStatus status) { for (int index = 0; index < amount; index++) { - final Target target = new Target(prefix + index); + final JpaTarget target = new JpaTarget(prefix + index); final Target sTarget = targetRepository.save(target); - final TargetInfo targetInfo = sTarget.getTargetInfo(); + final JpaTargetInfo targetInfo = (JpaTargetInfo) sTarget.getTargetInfo(); targetInfo.setUpdateStatus(status); targetInfoRepository.save(targetInfo); } @@ -537,9 +533,9 @@ public class ReportManagementTest extends AbstractIntegrationTest { private List sendUpdateActionStatusToTargets(final DistributionSet dsA, final Iterable targs, final Status status, final String... msgs) { - final List result = new ArrayList(); + final List result = new ArrayList<>(); for (final Target t : targs) { - final List findByTarget = actionRepository.findByTarget(t); + final List findByTarget = actionRepository.findByTarget((JpaTarget) t); for (final Action action : findByTarget) { result.add(sendUpdateActionStatusToTarget(status, action, t, msgs)); } @@ -551,14 +547,14 @@ public class ReportManagementTest extends AbstractIntegrationTest { final String... msgs) { updActA.setStatus(status); - final ActionStatus statusMessages = new ActionStatus(); + final ActionStatus statusMessages = new JpaActionStatus(); statusMessages.setAction(updActA); statusMessages.setOccurredAt(System.currentTimeMillis()); statusMessages.setStatus(status); for (final String msg : msgs) { statusMessages.addMessage(msg); } - controllerManagament.addUpdateActionStatus(statusMessages, updActA); + controllerManagament.addUpdateActionStatus(statusMessages); return targetManagement.findTargetByControllerID(t.getControllerId()); } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/RolloutManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java similarity index 93% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/RolloutManagementTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java index 22f9ee8b4..381e9722d 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/RolloutManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; @@ -16,27 +16,31 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.TestDataUtil; +import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; +import org.eclipse.hawkbit.repository.RolloutGroupManagement; +import org.eclipse.hawkbit.repository.RolloutManagement; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; +import org.eclipse.hawkbit.repository.jpa.utils.MultipleInvokeHelper; +import org.eclipse.hawkbit.repository.jpa.utils.SuccessCondition; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; -import org.eclipse.hawkbit.repository.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.utils.MultipleInvokeHelper; -import org.eclipse.hawkbit.repository.utils.SuccessCondition; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Description; @@ -44,7 +48,8 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; -import org.springframework.data.jpa.domain.Specification; + +import com.google.common.collect.Lists; import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; @@ -57,7 +62,7 @@ import ru.yandex.qatools.allure.annotations.Stories; */ @Features("Component Tests - Repository") @Stories("Rollout Management") -public class RolloutManagementTest extends AbstractIntegrationTest { +public class RolloutManagementTest extends AbstractJpaIntegrationTest { @Autowired private RolloutManagement rolloutManagement; @@ -134,10 +139,10 @@ public class RolloutManagementTest extends AbstractIntegrationTest { Status.RUNNING); // finish one action should be sufficient due the finish condition is at // 50% - final Action action = runningActions.get(0); + final JpaAction action = (JpaAction) runningActions.get(0); action.setStatus(Status.FINISHED); - controllerManagament.addUpdateActionStatus( - new ActionStatus(action, Status.FINISHED, System.currentTimeMillis(), ""), action); + controllerManagament + .addUpdateActionStatus(new JpaActionStatus(action, Status.FINISHED, System.currentTimeMillis(), "")); // check running rollouts again, now the finish condition should be hit // and should start the next group @@ -179,7 +184,7 @@ public class RolloutManagementTest extends AbstractIntegrationTest { for (final Action action : runningActions) { action.setStatus(Status.ERROR); controllerManagament.addUpdateActionStatus( - new ActionStatus(action, Status.ERROR, System.currentTimeMillis(), ""), action); + new JpaActionStatus((JpaAction) action, Status.ERROR, System.currentTimeMillis(), "")); } // check running rollouts again, now the error condition should be hit @@ -221,7 +226,7 @@ public class RolloutManagementTest extends AbstractIntegrationTest { for (final Action action : runningActions) { action.setStatus(Status.ERROR); controllerManagament.addUpdateActionStatus( - new ActionStatus(action, Status.ERROR, System.currentTimeMillis(), ""), action); + new JpaActionStatus((JpaAction) action, Status.ERROR, System.currentTimeMillis(), "")); } // check running rollouts again, now the error condition should be hit @@ -452,8 +457,7 @@ public class RolloutManagementTest extends AbstractIntegrationTest { targetToCancel.add(targetList.get(0)); targetToCancel.add(targetList.get(1)); targetToCancel.add(targetList.get(2)); - final DistributionSet dsForCancelTest = TestDataUtil.generateDistributionSet("dsForTest", softwareManagement, - distributionSetManagement); + final DistributionSet dsForCancelTest = testdataFactory.createDistributionSet("dsForTest"); deploymentManagement.assignDistributionSet(dsForCancelTest, targetToCancel); // 5 targets are canceling but still have the status running and 5 are // still in SCHEDULED @@ -477,8 +481,7 @@ public class RolloutManagementTest extends AbstractIntegrationTest { rolloutManagement.startRollout(rolloutOne); rolloutOne = rolloutManagement.findRolloutById(rolloutOne.getId()); - final DistributionSet dsForRolloutTwo = TestDataUtil.generateDistributionSet("dsForRolloutTwo", - softwareManagement, distributionSetManagement); + final DistributionSet dsForRolloutTwo = testdataFactory.createDistributionSet("dsForRolloutTwo"); final Rollout rolloutTwo = createRolloutByVariables("rolloutTwo", "This is the description for rollout two", 1, "controllerId==rollout-*", dsForRolloutTwo, "50", "80"); @@ -831,28 +834,27 @@ public class RolloutManagementTest extends AbstractIntegrationTest { Rollout myRollout = createTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout, amountGroups, successCondition, errorCondition, rolloutName, rolloutName); - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountOtherTargets, "others-", "rollout")); + targetManagement.createTargets(testdataFactory.generateTargets(amountOtherTargets, "others-", "rollout")); final String rsqlParam = "controllerId==*MyRoll*"; - final Specification rsqlSpecification = RSQLUtility.parse(rsqlParam, TargetFields.class); rolloutManagement.startRollout(myRollout); myRollout = rolloutManagement.findRolloutById(myRollout.getId()); final List rolloutGroups = myRollout.getRolloutGroups(); - Page targetPage = rolloutGroupManagement.findRolloutGroupTargets(rolloutGroups.get(0), - rsqlSpecification, new OffsetBasedPageRequest(0, 100, new Sort(Direction.ASC, "controllerId"))); + Page targetPage = rolloutGroupManagement.findRolloutGroupTargets(rolloutGroups.get(0), rsqlParam, + new OffsetBasedPageRequest(0, 100, new Sort(Direction.ASC, "controllerId"))); final List targetlistGroup1 = targetPage.getContent(); assertThat(targetlistGroup1.size()).isEqualTo(5); assertThat(targetlistGroup1.get(0).getControllerId()).isEqualTo("MyRollout--00000"); - targetPage = rolloutGroupManagement.findRolloutGroupTargets(rolloutGroups.get(1), rsqlSpecification, + targetPage = rolloutGroupManagement.findRolloutGroupTargets(rolloutGroups.get(1), rsqlParam, new OffsetBasedPageRequest(0, 100, new Sort(Direction.DESC, "controllerId"))); final List targetlistGroup2 = targetPage.getContent(); assertThat(targetlistGroup2.size()).isEqualTo(5); assertThat(targetlistGroup2.get(0).getControllerId()).isEqualTo("MyRollout--00009"); - targetPage = rolloutGroupManagement.findRolloutGroupTargets(rolloutGroups.get(2), rsqlSpecification, + targetPage = rolloutGroupManagement.findRolloutGroupTargets(rolloutGroups.get(2), rsqlParam, new OffsetBasedPageRequest(0, 100, new Sort(Direction.ASC, "controllerId"))); final List targetlistGroup3 = targetPage.getContent(); assertThat(targetlistGroup3.size()).isEqualTo(5); @@ -870,15 +872,14 @@ public class RolloutManagementTest extends AbstractIntegrationTest { final String errorCondition = "80"; final String rolloutName = "rolloutTest"; final String targetPrefixName = rolloutName; - final DistributionSet distributionSet = TestDataUtil.generateDistributionSet("dsFor" + rolloutName, - softwareManagement, distributionSetManagement); + final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName); targetManagement.createTargets( - TestDataUtil.buildTargetFixtures(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName)); - final RolloutGroupConditions conditions = new RolloutGroup.RolloutGroupConditionBuilder() + testdataFactory.generateTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName)); + final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder() .successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition) .errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition) .errorAction(RolloutGroupErrorAction.PAUSE, null).build(); - Rollout myRollout = new Rollout(); + Rollout myRollout = new JpaRollout(); myRollout.setName(rolloutName); myRollout.setDescription("This is a test description for the rollout"); myRollout.setTargetFilterQuery("controllerId==" + targetPrefixName + "-*"); @@ -931,17 +932,14 @@ public class RolloutManagementTest extends AbstractIntegrationTest { private Rollout createSimpleTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout, final int amountOtherTargets, final int groupSize, final String successCondition, final String errorCondition) { - final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); - final SoftwareModule jvm = softwareManagement - .createSoftwareModule(new SoftwareModule(runtimeType, "oracle-jre", "1.7.2", null, "")); - final SoftwareModule os = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "poky", "3.0.2", null, "")); - final DistributionSet rolloutDS = distributionSetManagement.createDistributionSet( - TestDataUtil.buildDistributionSet("rolloutDS", "0.0.0", standardDsType, os, jvm, ah)); - targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(amountTargetsForRollout, "rollout-", "rollout")); - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountOtherTargets, "others-", "rollout")); + final SoftwareModule ah = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_APP); + final SoftwareModule jvm = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_RT); + final SoftwareModule os = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_OS); + + final DistributionSet rolloutDS = distributionSetManagement.createDistributionSet(testdataFactory + .generateDistributionSet("rolloutDS", "0.0.0", standardDsType, Lists.newArrayList(os, jvm, ah))); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargetsForRollout, "rollout-", "rollout")); + targetManagement.createTargets(testdataFactory.generateTargets(amountOtherTargets, "others-", "rollout")); final String filterQuery = "controllerId==rollout-*"; return createRolloutByVariables("test-rollout-name-1", "test-rollout-description-1", groupSize, filterQuery, rolloutDS, successCondition, errorCondition); @@ -950,10 +948,9 @@ public class RolloutManagementTest extends AbstractIntegrationTest { private Rollout createTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout, final int groupSize, final String successCondition, final String errorCondition, final String rolloutName, final String targetPrefixName) { - final DistributionSet dsForRolloutTwo = TestDataUtil.generateDistributionSet("dsFor" + rolloutName, - softwareManagement, distributionSetManagement); + final DistributionSet dsForRolloutTwo = testdataFactory.createDistributionSet("dsFor" + rolloutName); targetManagement.createTargets( - TestDataUtil.buildTargetFixtures(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName)); + testdataFactory.generateTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName)); return createRolloutByVariables(rolloutName, rolloutName + "description", groupSize, "controllerId==" + targetPrefixName + "-*", dsForRolloutTwo, successCondition, errorCondition); } @@ -961,11 +958,11 @@ public class RolloutManagementTest extends AbstractIntegrationTest { private Rollout createRolloutByVariables(final String rolloutName, final String rolloutDescription, final int groupSize, final String filterQuery, final DistributionSet distributionSet, final String successCondition, final String errorCondition) { - final RolloutGroupConditions conditions = new RolloutGroup.RolloutGroupConditionBuilder() + final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder() .successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition) .errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition) .errorAction(RolloutGroupErrorAction.PAUSE, null).build(); - final Rollout rolloutToCreate = new Rollout(); + final Rollout rolloutToCreate = new JpaRollout(); rolloutToCreate.setName(rolloutName); rolloutToCreate.setDescription(rolloutDescription); rolloutToCreate.setTargetFilterQuery(filterQuery); @@ -977,8 +974,8 @@ public class RolloutManagementTest extends AbstractIntegrationTest { final List runningActions = deploymentManagement.findActionsByRolloutAndStatus(rollout, Status.RUNNING); for (final Action action : runningActions) { action.setStatus(status); - controllerManagament.addUpdateActionStatus(new ActionStatus(action, status, System.currentTimeMillis(), ""), - action); + controllerManagament.addUpdateActionStatus( + new JpaActionStatus((JpaAction) action, status, System.currentTimeMillis(), "")); } return runningActions.size(); } @@ -989,14 +986,13 @@ public class RolloutManagementTest extends AbstractIntegrationTest { assertThat(runningActions.size()).isGreaterThanOrEqualTo(amountOfTargetsToGetChanged); for (int i = 0; i < amountOfTargetsToGetChanged; i++) { controllerManagament.addUpdateActionStatus( - new ActionStatus(runningActions.get(i), status, System.currentTimeMillis(), ""), - runningActions.get(i)); + new JpaActionStatus((JpaAction) runningActions.get(i), status, System.currentTimeMillis(), "")); } return runningActions.size(); } - private Map createInitStatusMap() { - final Map map = new HashMap(); + private static Map createInitStatusMap() { + final Map map = new HashMap<>(); for (final TotalTargetCountStatus.Status status : TotalTargetCountStatus.Status.values()) { map.put(status, 0L); } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/SoftwareManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SoftwareManagementTest.java similarity index 75% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/SoftwareManagementTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SoftwareManagementTest.java index 849cf8e30..75633a85a 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/SoftwareManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SoftwareManagementTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.assertTrue; @@ -20,24 +20,26 @@ import java.util.Iterator; import java.util.List; import org.apache.commons.lang3.RandomUtils; -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; -import org.eclipse.hawkbit.RandomGeneratedInputStream; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.WithUser; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; +import org.eclipse.hawkbit.repository.jpa.model.JpaLocalArtifact; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Artifact; -import org.eclipse.hawkbit.repository.model.CustomSoftwareModule; +import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.model.SwMetadataCompositeKey; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.Test; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -53,13 +55,13 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("Software Management") -public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { +public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoDB { @Test @Description("Try to update non updatable fields results in repository doing nothing.") public void updateTypeNonUpdateableFieldsFails() { final SoftwareModuleType created = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test-key", "test-name", "test-desc", 1)); + .createSoftwareModuleType(new JpaSoftwareModuleType("test-key", "test-name", "test-desc", 1)); created.setName("a new name"); final SoftwareModuleType updated = softwareManagement.updateSoftwareModuleType(created); @@ -73,7 +75,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Calling update without changing fields results in no recorded change in the repository including unchanged audit fields.") public void updateNothingResultsInUnchangedRepositoryForType() { final SoftwareModuleType created = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test-key", "test-name", "test-desc", 1)); + .createSoftwareModuleType(new JpaSoftwareModuleType("test-key", "test-name", "test-desc", 1)); final SoftwareModuleType updated = softwareManagement.updateSoftwareModuleType(created); @@ -86,7 +88,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Calling update for changed fields results in change in the repository.") public void updateSoftareModuleTypeFieldsToNewValue() { final SoftwareModuleType created = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test-key", "test-name", "test-desc", 1)); + .createSoftwareModuleType(new JpaSoftwareModuleType("test-key", "test-name", "test-desc", 1)); created.setDescription("changed"); created.setColour("changed"); @@ -103,7 +105,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Try to update non updatable fields results in repository doing nothing.") public void updateNonUpdateableFieldsFails() { final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, "")); ah.setName("a new name"); final SoftwareModule updated = softwareManagement.updateSoftwareModule(ah); @@ -117,7 +119,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Calling update without changing fields results in no recorded change in the repository including unchanged audit fields.") public void updateNothingResultsInUnchangedRepository() { final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, "")); final SoftwareModule updated = softwareManagement.updateSoftwareModule(ah); @@ -130,7 +132,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Calling update for changed fields results in change in the repository.") public void updateSoftareModuleFieldsToNewValue() { final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", "test desc", "test vendor")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", "test desc", "test vendor")); ah.setDescription("changed"); ah.setVendor("changed"); @@ -146,7 +148,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Create Software Module call fails when called for existing entity.") public void createModuleCallFailsForExistingModule() { final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", "test desc", "test vendor")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", "test desc", "test vendor")); try { softwareManagement.createSoftwareModule(ah); fail("Should not have worked as module already exists."); @@ -159,8 +161,8 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Create Software Modules call fails when called for existing entities.") public void createModulesCallFailsForExistingModule() { final List modules = softwareManagement.createSoftwareModule( - Lists.newArrayList(new SoftwareModule(appType, "agent-hub", "1.0.1", "test desc", "test vendor"), - new SoftwareModule(appType, "agent-hub", "1.0.2", "test desc", "test vendor"))); + Lists.newArrayList(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", "test desc", "test vendor"), + new JpaSoftwareModule(appType, "agent-hub", "1.0.2", "test desc", "test vendor"))); try { softwareManagement.createSoftwareModule(modules); fail("Should not have worked as module already exists."); @@ -173,7 +175,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Create Software Module Type call fails when called for existing entity.") public void createModuleTypeCallFailsForExistingType() { final SoftwareModuleType created = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test-key", "test-name", "test-desc", 1)); + .createSoftwareModuleType(new JpaSoftwareModuleType("test-key", "test-name", "test-desc", 1)); try { softwareManagement.createSoftwareModuleType(created); @@ -187,8 +189,8 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Create Software Module Types call fails when called for existing entities.") public void createModuleTypesCallFailsForExistingTypes() { final List created = softwareManagement.createSoftwareModuleType( - Lists.newArrayList(new SoftwareModuleType("test-key-bumlux", "test-name", "test-desc", 1), - new SoftwareModuleType("test-key-bumlux2", "test-name2", "test-desc", 1))); + Lists.newArrayList(new JpaSoftwareModuleType("test-key-bumlux", "test-name", "test-desc", 1), + new JpaSoftwareModuleType("test-key-bumlux2", "test-name2", "test-desc", 1))); try { softwareManagement.createSoftwareModuleType(created); @@ -202,7 +204,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Calling update for changing fields to null results in change in the repository.") public void eraseSoftareModuleFields() { final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", "test desc", "test vendor")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", "test desc", "test vendor")); ah.setDescription(null); ah.setVendor(null); @@ -218,19 +220,19 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("searched for software modules based on the various filter options, e.g. name,desc,type, version.") public void findSoftwareModuleByFilters() { final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, "")); final SoftwareModule jvm = softwareManagement - .createSoftwareModule(new SoftwareModule(runtimeType, "oracle-jre", "1.7.2", null, "")); + .createSoftwareModule(new JpaSoftwareModule(runtimeType, "oracle-jre", "1.7.2", null, "")); final SoftwareModule os = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "poky", "3.0.2", null, "")); + .createSoftwareModule(new JpaSoftwareModule(osType, "poky", "3.0.2", null, "")); final SoftwareModule ah2 = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.2", null, "")); - DistributionSet ds = distributionSetManagement.createDistributionSet( - TestDataUtil.buildDistributionSet("ds-1", "1.0.1", standardDsType, os, jvm, ah2)); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.2", null, "")); + JpaDistributionSet ds = (JpaDistributionSet) distributionSetManagement.createDistributionSet(testdataFactory + .generateDistributionSet("ds-1", "1.0.1", standardDsType, Lists.newArrayList(os, jvm, ah2))); - final Target target = targetManagement.createTarget(new Target("test123")); - ds = assignSet(target, ds).getDistributionSet(); + final JpaTarget target = (JpaTarget) targetManagement.createTarget(new JpaTarget("test123")); + ds = (JpaDistributionSet) assignSet(target, ds).getDistributionSet(); // standard searches assertThat(softwareManagement.findSoftwareModuleByFilters(pageReq, "poky", osType).getContent()).hasSize(1); @@ -254,7 +256,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { .isEqualTo(ah); } - private Action assignSet(final Target target, final DistributionSet ds) { + private Action assignSet(final JpaTarget target, final JpaDistributionSet ds) { deploymentManagement.assignDistributionSet(ds.getId(), new String[] { target.getControllerId() }); assertThat( targetManagement.findTargetByControllerID(target.getControllerId()).getTargetInfo().getUpdateStatus()) @@ -270,12 +272,12 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Searches for software modules based on a list of IDs.") public void findSoftwareModulesById() { - final List modules = new ArrayList(); + final List modules = new ArrayList<>(); - modules.add(softwareManagement.createSoftwareModule(new SoftwareModule(osType, "poky-una", "3.0.2", null, "")) - .getId()); - modules.add(softwareManagement.createSoftwareModule(new SoftwareModule(osType, "poky-u2na", "3.0.3", null, "")) - .getId()); + modules.add(softwareManagement + .createSoftwareModule(new JpaSoftwareModule(osType, "poky-una", "3.0.2", null, "")).getId()); + modules.add(softwareManagement + .createSoftwareModule(new JpaSoftwareModule(osType, "poky-u2na", "3.0.3", null, "")).getId()); modules.add(624355263L); assertThat(softwareManagement.findSoftwareModulesById(modules)).hasSize(2); @@ -286,13 +288,13 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { public void findSoftwareModulesByType() { // found in test final SoftwareModule one = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "one", "one", null, "")); + .createSoftwareModule(new JpaSoftwareModule(osType, "one", "one", null, "")); final SoftwareModule two = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "two", "two", null, "")); + .createSoftwareModule(new JpaSoftwareModule(osType, "two", "two", null, "")); // ignored softwareManagement.deleteSoftwareModule( - softwareManagement.createSoftwareModule(new SoftwareModule(osType, "deleted", "deleted", null, ""))); - softwareManagement.createSoftwareModule(new SoftwareModule(appType, "three", "3.0.2", null, "")); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(osType, "deleted", "deleted", null, ""))); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(appType, "three", "3.0.2", null, "")); assertThat(softwareManagement.findSoftwareModulesByType(pageReq, osType).getContent()) .as("Expected to find the following number of modules:").hasSize(2).as("with the following elements") @@ -303,11 +305,11 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Counts all software modules in the repsitory that are not marked as deleted.") public void countSoftwareModulesAll() { // found in test - softwareManagement.createSoftwareModule(new SoftwareModule(osType, "one", "one", null, "")); - softwareManagement.createSoftwareModule(new SoftwareModule(appType, "two", "two", null, "")); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(osType, "one", "one", null, "")); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(appType, "two", "two", null, "")); // ignored softwareManagement.deleteSoftwareModule( - softwareManagement.createSoftwareModule(new SoftwareModule(osType, "deleted", "deleted", null, ""))); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(osType, "deleted", "deleted", null, ""))); assertThat(softwareManagement.countSoftwareModulesAll()).as("Expected to find the following number of modules:") .isEqualTo(2); @@ -317,13 +319,13 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Counts for software modules by type.") public void countSoftwareModulesByType() { // found in test - softwareManagement.createSoftwareModule(new SoftwareModule(osType, "one", "one", null, "")); - softwareManagement.createSoftwareModule(new SoftwareModule(osType, "two", "two", null, "")); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(osType, "one", "one", null, "")); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(osType, "two", "two", null, "")); // ignored softwareManagement.deleteSoftwareModule( - softwareManagement.createSoftwareModule(new SoftwareModule(osType, "deleted", "deleted", null, ""))); - softwareManagement.createSoftwareModule(new SoftwareModule(appType, "three", "3.0.2", null, "")); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(osType, "deleted", "deleted", null, ""))); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(appType, "three", "3.0.2", null, "")); assertThat(softwareManagement.countSoftwareModulesByType(osType)) .as("Expected to find the following number of modules:").isEqualTo(2); @@ -336,7 +338,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { appType); SoftwareModuleType type = softwareManagement.createSoftwareModuleType( - new SoftwareModuleType("bundle", "OSGi Bundle", "fancy stuff", Integer.MAX_VALUE)); + new JpaSoftwareModuleType("bundle", "OSGi Bundle", "fancy stuff", Integer.MAX_VALUE)); assertThat(softwareManagement.findSoftwareModuleTypesAll(pageReq)).hasSize(4).contains(osType, runtimeType, appType, type); @@ -345,23 +347,25 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { softwareManagement.deleteSoftwareModuleType(type); assertThat(softwareManagement.findSoftwareModuleTypesAll(pageReq)).hasSize(3).contains(osType, runtimeType, appType); - assertThat(softwareModuleTypeRepository.findAll()).hasSize(3).contains(osType, runtimeType, appType); + assertThat(softwareModuleTypeRepository.findAll()).hasSize(3).contains((JpaSoftwareModuleType) osType, + (JpaSoftwareModuleType) runtimeType, (JpaSoftwareModuleType) appType); type = softwareManagement.createSoftwareModuleType( - new SoftwareModuleType("bundle2", "OSGi Bundle2", "fancy stuff", Integer.MAX_VALUE)); + new JpaSoftwareModuleType("bundle2", "OSGi Bundle2", "fancy stuff", Integer.MAX_VALUE)); assertThat(softwareManagement.findSoftwareModuleTypesAll(pageReq)).hasSize(4).contains(osType, runtimeType, appType, type); softwareManagement - .createSoftwareModule(new SoftwareModule(type, "Test SM", "1.0", "cool module", "from meeee")); + .createSoftwareModule(new JpaSoftwareModule(type, "Test SM", "1.0", "cool module", "from meeee")); // delete assigned softwareManagement.deleteSoftwareModuleType(type); assertThat(softwareManagement.findSoftwareModuleTypesAll(pageReq)).hasSize(3).contains(osType, runtimeType, appType); - assertThat(softwareModuleTypeRepository.findAll()).hasSize(4).contains(osType, runtimeType, appType, + assertThat(softwareModuleTypeRepository.findAll()).hasSize(4).contains((JpaSoftwareModuleType) osType, + (JpaSoftwareModuleType) runtimeType, (JpaSoftwareModuleType) appType, softwareModuleTypeRepository.findOne(type.getId())); } @@ -397,7 +401,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { // Init DistributionSet final DistributionSet disSet = distributionSetManagement - .createDistributionSet(new DistributionSet("ds1", "v1.0", "test ds", standardDsType, null)); + .createDistributionSet(new JpaDistributionSet("ds1", "v1.0", "test ds", standardDsType, null)); // [STEP1]: Create SoftwareModuleX with ArtifactX SoftwareModule assignedModule = createSoftwareModuleWithArtifacts(osType, "moduleX", "3.0.2", 2); @@ -431,9 +435,9 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { public void softDeleteOfHistoricalAssignedArtifact() { // Init target and DistributionSet - final Target target = targetManagement.createTarget(new Target("test123")); + final Target target = targetManagement.createTarget(new JpaTarget("test123")); final DistributionSet disSet = distributionSetManagement - .createDistributionSet(new DistributionSet("ds1", "v1.0", "test ds", standardDsType, null)); + .createDistributionSet(new JpaDistributionSet("ds1", "v1.0", "test ds", standardDsType, null)); // [STEP1]: Create SoftwareModuleX and include the new ArtifactX SoftwareModule assignedModule = createSoftwareModuleWithArtifacts(osType, "moduleX", "3.0.2", 2); @@ -525,11 +529,11 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { // Init artifact binary data, target and DistributionSets final byte[] source = RandomUtils.nextBytes(1024); - final Target target = targetManagement.createTarget(new Target("test123")); + final Target target = targetManagement.createTarget(new JpaTarget("test123")); final DistributionSet disSetX = distributionSetManagement - .createDistributionSet(new DistributionSet("dsX", "v1.0", "test dsX", standardDsType, null)); + .createDistributionSet(new JpaDistributionSet("dsX", "v1.0", "test dsX", standardDsType, null)); final DistributionSet disSetY = distributionSetManagement - .createDistributionSet(new DistributionSet("dsY", "v1.0", "test dsY", standardDsType, null)); + .createDistributionSet(new JpaDistributionSet("dsY", "v1.0", "test dsY", standardDsType, null)); // [STEP1]: Create SoftwareModuleX and add a new ArtifactX SoftwareModule moduleX = createSoftwareModuleWithArtifacts(osType, "modulex", "v1.0", 0); @@ -587,8 +591,8 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { final long countSoftwareModule = softwareModuleRepository.count(); // create SoftwareModule - SoftwareModule softwareModule = softwareManagement - .createSoftwareModule(new SoftwareModule(type, name, version, "description of artifact " + name, "")); + SoftwareModule softwareModule = softwareManagement.createSoftwareModule( + new JpaSoftwareModule(type, name, version, "description of artifact " + name, "")); for (int i = 0; i < numberArtifacts; i++) { artifactManagement.createLocalArtifact(new RandomGeneratedInputStream(5 * 1024), softwareModule.getId(), @@ -617,7 +621,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { for (final Artifact result : results) { assertThat(result.getId()).isNotNull(); assertThat(operations.findOne(new Query() - .addCriteria(Criteria.where("filename").is(((LocalArtifact) result).getGridFsFileName())))) + .addCriteria(Criteria.where("filename").is(((JpaLocalArtifact) result).getGridFsFileName())))) .isNotNull(); } } @@ -625,7 +629,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { private void assertArtfiactNull(final Artifact... results) { for (final Artifact result : results) { assertThat(operations.findOne(new Query() - .addCriteria(Criteria.where("filename").is(((LocalArtifact) result).getGridFsFileName())))) + .addCriteria(Criteria.where("filename").is(((JpaLocalArtifact) result).getGridFsFileName())))) .isNull(); } } @@ -635,28 +639,28 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { public void findSoftwareModuleOrderByDistributionModuleNameAscModuleVersionAsc() { // test meta data final SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("thetype", "thename", "desc", 100)); + .createSoftwareModuleType(new JpaSoftwareModuleType("thetype", "thename", "desc", 100)); final DistributionSetType testDsType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("key", "name", "desc").addMandatoryModuleType(osType) - .addOptionalModuleType(testType)); + .createDistributionSetType(new JpaDistributionSetType("key", "name", "desc") + .addMandatoryModuleType(osType).addOptionalModuleType(testType)); // found in test final SoftwareModule unassigned = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "asis", "found", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "asis", "found", null, "")); final SoftwareModule one = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "found", "b", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "found", "b", null, "")); final SoftwareModule two = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "found", "c", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "found", "c", null, "")); final SoftwareModule differentName = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "differentname", "d", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "differentname", "d", null, "")); // ignored final SoftwareModule deleted = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "deleted", "deleted", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "deleted", "deleted", null, "")); final SoftwareModule four = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "sdfjhsdj", "e", null, "")); + .createSoftwareModule(new JpaSoftwareModule(osType, "sdfjhsdj", "e", null, "")); - final DistributionSet set = distributionSetManagement.createDistributionSet(new DistributionSet("set", "1", + final DistributionSet set = distributionSetManagement.createDistributionSet(new JpaDistributionSet("set", "1", "desc", testDsType, Lists.newArrayList(one, two, deleted, four, differentName))); softwareManagement.deleteSoftwareModule(deleted); @@ -664,22 +668,22 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { assertThat(softwareManagement.findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(pageReq, set.getId(), "found", testType).getContent()) .as("Found modules with given name, given module type and the assigned ones first") - .containsExactly(new CustomSoftwareModule(one, true), new CustomSoftwareModule(two, true), - new CustomSoftwareModule(unassigned, false)); + .containsExactly(new AssignedSoftwareModule(one, true), new AssignedSoftwareModule(two, true), + new AssignedSoftwareModule(unassigned, false)); // with filter on module type only assertThat(softwareManagement.findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(pageReq, set.getId(), null, testType).getContent()) .as("Found modules with given module type and the assigned ones first").containsExactly( - new CustomSoftwareModule(differentName, true), new CustomSoftwareModule(one, true), - new CustomSoftwareModule(two, true), new CustomSoftwareModule(unassigned, false)); + new AssignedSoftwareModule(differentName, true), new AssignedSoftwareModule(one, true), + new AssignedSoftwareModule(two, true), new AssignedSoftwareModule(unassigned, false)); // without any filter assertThat(softwareManagement.findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(pageReq, set.getId(), null, null).getContent()).as("Found modules with the assigned ones first").containsExactly( - new CustomSoftwareModule(differentName, true), new CustomSoftwareModule(one, true), - new CustomSoftwareModule(two, true), new CustomSoftwareModule(four, true), - new CustomSoftwareModule(unassigned, false)); + new AssignedSoftwareModule(differentName, true), new AssignedSoftwareModule(one, true), + new AssignedSoftwareModule(two, true), new AssignedSoftwareModule(four, true), + new AssignedSoftwareModule(unassigned, false)); } @Test @@ -688,26 +692,26 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { // test meta data final SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("thetype", "thename", "desc", 100)); + .createSoftwareModuleType(new JpaSoftwareModuleType("thetype", "thename", "desc", 100)); final DistributionSetType testDsType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("key", "name", "desc").addMandatoryModuleType(osType) - .addOptionalModuleType(testType)); + .createDistributionSetType(new JpaDistributionSetType("key", "name", "desc") + .addMandatoryModuleType(osType).addOptionalModuleType(testType)); // test modules - softwareManagement.createSoftwareModule(new SoftwareModule(testType, "asis", "found", null, "")); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(testType, "asis", "found", null, "")); final SoftwareModule one = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "found", "b", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "found", "b", null, "")); final SoftwareModule two = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "found", "c", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "found", "c", null, "")); final SoftwareModule differentName = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "differentname", "d", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "differentname", "d", null, "")); final SoftwareModule four = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "found", "3.0.2", null, "")); + .createSoftwareModule(new JpaSoftwareModule(osType, "found", "3.0.2", null, "")); // one soft deleted final SoftwareModule deleted = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "deleted", "deleted", null, "")); - distributionSetManagement.createDistributionSet(new DistributionSet("set", "1", "desc", testDsType, + .createSoftwareModule(new JpaSoftwareModule(testType, "deleted", "deleted", null, "")); + distributionSetManagement.createDistributionSet(new JpaDistributionSet("set", "1", "desc", testDsType, Lists.newArrayList(one, two, deleted, four, differentName))); softwareManagement.deleteSoftwareModule(deleted); @@ -724,18 +728,18 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Verfies that all undeleted software modules are found in the repository.") public void countSoftwareModuleTypesAll() { final SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("thetype", "thename", "desc", 100)); + .createSoftwareModuleType(new JpaSoftwareModuleType("thetype", "thename", "desc", 100)); final DistributionSetType testDsType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("key", "name", "desc").addMandatoryModuleType(osType) - .addOptionalModuleType(testType)); + .createDistributionSetType(new JpaDistributionSetType("key", "name", "desc") + .addMandatoryModuleType(osType).addOptionalModuleType(testType)); final SoftwareModule four = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "found", "3.0.2", null, "")); + .createSoftwareModule(new JpaSoftwareModule(osType, "found", "3.0.2", null, "")); // one soft deleted final SoftwareModule deleted = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "deleted", "deleted", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "deleted", "deleted", null, "")); distributionSetManagement.createDistributionSet( - new DistributionSet("set", "1", "desc", testDsType, Lists.newArrayList(deleted, four))); + new JpaDistributionSet("set", "1", "desc", testDsType, Lists.newArrayList(deleted, four))); softwareManagement.deleteSoftwareModule(deleted); assertThat(softwareManagement.countSoftwareModulesAll()).as("Number of undeleted modules").isEqualTo(1); @@ -746,8 +750,8 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Checks that software module typeis found based on given name.") public void findSoftwareModuleTypeByName() { final SoftwareModuleType found = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("thetype", "thename", "desc", 100)); - softwareManagement.createSoftwareModuleType(new SoftwareModuleType("thetype2", "anothername", "desc", 100)); + .createSoftwareModuleType(new JpaSoftwareModuleType("thetype", "thename", "desc", 100)); + softwareManagement.createSoftwareModuleType(new JpaSoftwareModuleType("thetype2", "anothername", "desc", 100)); assertThat(softwareManagement.findSoftwareModuleTypeByName("thename")).as("Type with given name") .isEqualTo(found); @@ -757,7 +761,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Verfies that it is not possible to create a type that alrady exists.") public void createSoftwareModuleTypeFailsWithExistingEntity() { final SoftwareModuleType created = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("thetype", "thename", "desc", 100)); + .createSoftwareModuleType(new JpaSoftwareModuleType("thetype", "thename", "desc", 100)); try { softwareManagement.createSoftwareModuleType(created); fail("should not have worked as module type already exists"); @@ -771,10 +775,10 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Description("Verfies that it is not possible to create a list of types where one already exists.") public void createSoftwareModuleTypesFailsWithExistingEntity() { final SoftwareModuleType created = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("thetype", "thename", "desc", 100)); + .createSoftwareModuleType(new JpaSoftwareModuleType("thetype", "thename", "desc", 100)); try { softwareManagement.createSoftwareModuleType( - Lists.newArrayList(created, new SoftwareModuleType("anothertype", "anothername", "desc", 100))); + Lists.newArrayList(created, new JpaSoftwareModuleType("anothertype", "anothername", "desc", 100))); fail("should not have worked as module type already exists"); } catch (final EntityAlreadyExistsException e) { @@ -784,9 +788,9 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { @Test @Description("Verfies that multiple types are created as requested.") public void createMultipleoftwareModuleTypes() { - final List created = softwareManagement - .createSoftwareModuleType(Lists.newArrayList(new SoftwareModuleType("thetype", "thename", "desc", 100), - new SoftwareModuleType("thetype2", "thename2", "desc2", 100))); + final List created = softwareManagement.createSoftwareModuleType( + Lists.newArrayList(new JpaSoftwareModuleType("thetype", "thename", "desc", 100), + new JpaSoftwareModuleType("thetype2", "thename2", "desc2", 100))); assertThat(created.size()).as("Number of created types").isEqualTo(2); assertThat(softwareManagement.countSoftwareModuleTypesAll()).as("Number of types in repository").isEqualTo(5); @@ -797,23 +801,23 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { public void findSoftwareModuleByAssignedTo() { // test meta data final SoftwareModuleType testType = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("thetype", "thename", "desc", 100)); + .createSoftwareModuleType(new JpaSoftwareModuleType("thetype", "thename", "desc", 100)); final DistributionSetType testDsType = distributionSetManagement - .createDistributionSetType(new DistributionSetType("key", "name", "desc").addMandatoryModuleType(osType) - .addOptionalModuleType(testType)); + .createDistributionSetType(new JpaDistributionSetType("key", "name", "desc") + .addMandatoryModuleType(osType).addOptionalModuleType(testType)); // test modules - softwareManagement.createSoftwareModule(new SoftwareModule(testType, "asis", "found", null, "")); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(testType, "asis", "found", null, "")); final SoftwareModule one = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "found", "b", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "found", "b", null, "")); final SoftwareModule two = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "found", "c", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "found", "c", null, "")); // one soft deleted final SoftwareModule deleted = softwareManagement - .createSoftwareModule(new SoftwareModule(testType, "deleted", "deleted", null, "")); + .createSoftwareModule(new JpaSoftwareModule(testType, "deleted", "deleted", null, "")); final DistributionSet set = distributionSetManagement.createDistributionSet( - new DistributionSet("set", "1", "desc", testDsType, Lists.newArrayList(one, deleted))); + new JpaDistributionSet("set", "1", "desc", testDsType, Lists.newArrayList(one, deleted))); softwareManagement.deleteSoftwareModule(deleted); assertThat(softwareManagement.findSoftwareModuleByAssignedTo(pageReq, set).getContent()) @@ -831,13 +835,13 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { final String knownValue2 = "myKnownValue2"; final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, "")); assertThat(ah.getOptLockRevision()).isEqualTo(1L); - final SoftwareModuleMetadata swMetadata1 = new SoftwareModuleMetadata(knownKey1, ah, knownValue1); + final SoftwareModuleMetadata swMetadata1 = new JpaSoftwareModuleMetadata(knownKey1, ah, knownValue1); - final SoftwareModuleMetadata swMetadata2 = new SoftwareModuleMetadata(knownKey2, ah, knownValue2); + final SoftwareModuleMetadata swMetadata2 = new JpaSoftwareModuleMetadata(knownKey2, ah, knownValue2); final List softwareModuleMetadata = softwareManagement .createSoftwareModuleMetadata(Lists.newArrayList(swMetadata1, swMetadata2)); @@ -848,7 +852,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { assertThat(softwareModuleMetadata).hasSize(2); assertThat(softwareModuleMetadata.get(0)).isNotNull(); assertThat(softwareModuleMetadata.get(0).getValue()).isEqualTo(knownValue1); - assertThat(softwareModuleMetadata.get(0).getId().getKey()).isEqualTo(knownKey1); + assertThat(((JpaSoftwareModuleMetadata) softwareModuleMetadata.get(0)).getId().getKey()).isEqualTo(knownKey1); assertThat(softwareModuleMetadata.get(0).getSoftwareModule().getId()).isEqualTo(ah.getId()); } @@ -861,12 +865,12 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { final String knownValue2 = "myKnownValue2"; final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, "")); - softwareManagement.createSoftwareModuleMetadata(new SoftwareModuleMetadata(knownKey1, ah, knownValue1)); + softwareManagement.createSoftwareModuleMetadata(new JpaSoftwareModuleMetadata(knownKey1, ah, knownValue1)); try { - softwareManagement.createSoftwareModuleMetadata(new SoftwareModuleMetadata(knownKey1, ah, knownValue2)); + softwareManagement.createSoftwareModuleMetadata(new JpaSoftwareModuleMetadata(knownKey1, ah, knownValue2)); fail("should not have worked as module metadata already exists"); } catch (final EntityAlreadyExistsException e) { @@ -883,13 +887,13 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { // create a base software module final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, "")); // initial opt lock revision must be 1 assertThat(ah.getOptLockRevision()).isEqualTo(1L); // create an software module meta data entry final List softwareModuleMetadata = softwareManagement.createSoftwareModuleMetadata( - Collections.singleton(new SoftwareModuleMetadata(knownKey, ah, knownValue))); + Collections.singleton(new JpaSoftwareModuleMetadata(knownKey, ah, knownValue))); assertThat(softwareModuleMetadata).hasSize(1); // base software module should have now the opt lock revision one // because we are modifying the @@ -915,7 +919,7 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { // verify updated meta data contains the updated value assertThat(updated).isNotNull(); assertThat(updated.getValue()).isEqualTo(knownUpdateValue); - assertThat(updated.getId().getKey()).isEqualTo(knownKey); + assertThat(((JpaSoftwareModuleMetadata) updated).getId().getKey()).isEqualTo(knownKey); assertThat(updated.getSoftwareModule().getId()).isEqualTo(ah.getId()); } @@ -926,16 +930,16 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { final String knownValue1 = "myKnownValue1"; SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, "")); - ah = softwareManagement.createSoftwareModuleMetadata(new SoftwareModuleMetadata(knownKey1, ah, knownValue1)) + ah = softwareManagement.createSoftwareModuleMetadata(new JpaSoftwareModuleMetadata(knownKey1, ah, knownValue1)) .getSoftwareModule(); assertThat(softwareManagement.findSoftwareModuleById(ah.getId()).getMetadata()) .as("Contains the created metadata element") - .containsExactly(new SoftwareModuleMetadata(knownKey1, ah, knownValue1)); + .containsExactly(new JpaSoftwareModuleMetadata(knownKey1, ah, knownValue1)); - softwareManagement.deleteSoftwareModuleMetadata(new SwMetadataCompositeKey(ah, knownKey1)); + softwareManagement.deleteSoftwareModuleMetadata(ah, knownKey1); assertThat(softwareManagement.findSoftwareModuleById(ah.getId()).getMetadata()).as("Metadata elemenets are") .isEmpty(); } @@ -947,13 +951,13 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { final String knownValue1 = "myKnownValue1"; SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, "")); - ah = softwareManagement.createSoftwareModuleMetadata(new SoftwareModuleMetadata(knownKey1, ah, knownValue1)) + ah = softwareManagement.createSoftwareModuleMetadata(new JpaSoftwareModuleMetadata(knownKey1, ah, knownValue1)) .getSoftwareModule(); try { - softwareManagement.findSoftwareModuleMetadata(new SwMetadataCompositeKey(ah, "doesnotexist")); + softwareManagement.findSoftwareModuleMetadata(ah, "doesnotexist"); fail("should not have worked as module metadata with that key does not exist"); } catch (final EntityNotFoundException e) { @@ -965,20 +969,20 @@ public class SoftwareManagementTest extends AbstractIntegrationTestWithMongoDB { public void findAllSoftwareModuleMetadataBySwId() { SoftwareModule sw1 = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", null, "")); + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, "")); SoftwareModule sw2 = softwareManagement - .createSoftwareModule(new SoftwareModule(osType, "os", "1.0.1", null, "")); + .createSoftwareModule(new JpaSoftwareModule(osType, "os", "1.0.1", null, "")); for (int index = 0; index < 10; index++) { sw1 = softwareManagement - .createSoftwareModuleMetadata(new SoftwareModuleMetadata("key" + index, sw1, "value" + index)) + .createSoftwareModuleMetadata(new JpaSoftwareModuleMetadata("key" + index, sw1, "value" + index)) .getSoftwareModule(); } for (int index = 0; index < 20; index++) { sw2 = softwareManagement - .createSoftwareModuleMetadata(new SoftwareModuleMetadata("key" + index, sw2, "value" + index)) + .createSoftwareModuleMetadata(new JpaSoftwareModuleMetadata("key" + index, sw2, "value" + index)) .getSoftwareModule(); } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/SystemManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SystemManagementTest.java similarity index 81% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/SystemManagementTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SystemManagementTest.java index 1a1632d32..a9f004a73 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/SystemManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SystemManagementTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; @@ -14,13 +14,12 @@ import java.io.ByteArrayInputStream; import java.util.List; import java.util.Random; -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.WithSpringAuthorityRule; -import org.eclipse.hawkbit.report.model.TenantUsage; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TenantMetaData; +import org.eclipse.hawkbit.repository.report.model.TenantUsage; +import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule; import org.junit.Test; import ru.yandex.qatools.allure.annotations.Description; @@ -29,7 +28,16 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("System Management") -public class SystemManagementTest extends AbstractIntegrationTestWithMongoDB { +public class SystemManagementTest extends AbstractJpaIntegrationTestWithMongoDB { + + @Test + @Description("Ensures that you can create a tenant without setting the necessary security context which holds a current tenant") + public void createInitialTenantWithoutSecurityContext() { + securityRule.clear(); + final String tenantToBeCreated = "newTenantToCreate"; + final TenantMetaData tenantMetadata = systemManagement.getTenantMetadata(tenantToBeCreated); + assertThat(tenantMetadata).isNotNull(); + } @Test @Description("Ensures that findTenants returns all tenants and not only restricted to the tenant which currently is logged in") @@ -111,8 +119,8 @@ public class SystemManagementTest extends AbstractIntegrationTestWithMongoDB { final List createdTargets = createTestTargets(targets); if (updates > 0) { for (int x = 0; x < updates; x++) { - final DistributionSet ds = TestDataUtil.generateDistributionSet("to be deployed" + x, - softwareManagement, distributionSetManagement, true); + final DistributionSet ds = testdataFactory.createDistributionSet("to be deployed" + x, + true); deploymentManagement.assignDistributionSet(ds, createdTargets); } @@ -128,11 +136,11 @@ public class SystemManagementTest extends AbstractIntegrationTestWithMongoDB { private List createTestTargets(final int targets) { return targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(targets, "testTargetOfTenant", "testTargetOfTenant")); + .createTargets(testdataFactory.generateTargets(targets, "testTargetOfTenant", "testTargetOfTenant")); } private void createTestArtifact(final byte[] random) { - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", + JpaSoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", "version 1", null, null); sm = softwareModuleRepository.save(sm); @@ -140,8 +148,7 @@ public class SystemManagementTest extends AbstractIntegrationTestWithMongoDB { } private void createDeletedTestArtifact(final byte[] random) { - final DistributionSet ds = TestDataUtil.generateDistributionSet("deleted garbage", softwareManagement, - distributionSetManagement, true); + final DistributionSet ds = testdataFactory.createDistributionSet("deleted garbage", true); ds.getModules().stream().forEach(module -> { artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), module.getId(), "file1", false); softwareManagement.deleteSoftwareModule(module); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TagManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TagManagementTest.java similarity index 82% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TagManagementTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TagManagementTest.java index 4c6af0d83..5f2fe3fbd 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TagManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TagManagementTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; @@ -14,14 +14,16 @@ import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.stream.Collectors; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.repository.DistributionSetFilter.DistributionSetFilterBuilder; +import org.eclipse.hawkbit.repository.TagManagement; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder; import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; import org.eclipse.hawkbit.repository.model.Tag; @@ -44,7 +46,7 @@ import ru.yandex.qatools.allure.annotations.Stories; */ @Features("Component Tests - Repository") @Stories("Tag Management") -public class TagManagementTest extends AbstractIntegrationTest { +public class TagManagementTest extends AbstractJpaIntegrationTest { public TagManagementTest() { LOG = LoggerFactory.getLogger(TagManagementTest.class); } @@ -57,26 +59,19 @@ public class TagManagementTest extends AbstractIntegrationTest { @Test @Description("Full DS tag lifecycle tested. Create tags, assign them to sets and delete the tags.") public void createAndAssignAndDeleteDistributionSetTags() { - final List dsAs = TestDataUtil.generateDistributionSets("DS-A", 20, softwareManagement, - distributionSetManagement); - final List dsBs = TestDataUtil.generateDistributionSets("DS-B", 10, softwareManagement, - distributionSetManagement); - final List dsCs = TestDataUtil.generateDistributionSets("DS-C", 25, softwareManagement, - distributionSetManagement); - final List dsABs = TestDataUtil.generateDistributionSets("DS-AB", 5, softwareManagement, - distributionSetManagement); - final List dsACs = TestDataUtil.generateDistributionSets("DS-AC", 11, softwareManagement, - distributionSetManagement); - final List dsBCs = TestDataUtil.generateDistributionSets("DS-BC", 13, softwareManagement, - distributionSetManagement); - final List dsABCs = TestDataUtil.generateDistributionSets("DS-ABC", 9, softwareManagement, - distributionSetManagement); + final Collection dsAs = testdataFactory.createDistributionSets("DS-A", 20); + final Collection dsBs = testdataFactory.createDistributionSets("DS-B", 10); + final Collection dsCs = testdataFactory.createDistributionSets("DS-C", 25); + final Collection dsABs = testdataFactory.createDistributionSets("DS-AB", 5); + final Collection dsACs = testdataFactory.createDistributionSets("DS-AC", 11); + final Collection dsBCs = testdataFactory.createDistributionSets("DS-BC", 13); + final Collection dsABCs = testdataFactory.createDistributionSets("DS-ABC", 9); - final DistributionSetTag tagA = tagManagement.createDistributionSetTag(new DistributionSetTag("A")); - final DistributionSetTag tagB = tagManagement.createDistributionSetTag(new DistributionSetTag("B")); - final DistributionSetTag tagC = tagManagement.createDistributionSetTag(new DistributionSetTag("C")); - final DistributionSetTag tagX = tagManagement.createDistributionSetTag(new DistributionSetTag("X")); - final DistributionSetTag tagY = tagManagement.createDistributionSetTag(new DistributionSetTag("Y")); + final DistributionSetTag tagA = tagManagement.createDistributionSetTag(new JpaDistributionSetTag("A")); + final DistributionSetTag tagB = tagManagement.createDistributionSetTag(new JpaDistributionSetTag("B")); + final DistributionSetTag tagC = tagManagement.createDistributionSetTag(new JpaDistributionSetTag("C")); + final DistributionSetTag tagX = tagManagement.createDistributionSetTag(new JpaDistributionSetTag("X")); + final DistributionSetTag tagY = tagManagement.createDistributionSetTag(new JpaDistributionSetTag("Y")); distributionSetManagement.toggleTagAssignment(dsAs, tagA); distributionSetManagement.toggleTagAssignment(dsBs, tagB); @@ -167,20 +162,18 @@ public class TagManagementTest extends AbstractIntegrationTest { @Description("Verifies the toogle mechanism by means on assigning tag if at least on DS in the list does not have" + "the tag yet. Unassign if all of them have the tag already.") public void assignAndUnassignDistributionSetTags() { - final List groupA = TestDataUtil.generateDistributionSets(20, softwareManagement, - distributionSetManagement); - final List groupB = TestDataUtil.generateDistributionSets("unassigned", 20, softwareManagement, - distributionSetManagement); + final Collection groupA = testdataFactory.createDistributionSets(20); + final Collection groupB = testdataFactory.createDistributionSets("unassigned", 20); final DistributionSetTag tag = tagManagement - .createDistributionSetTag(new DistributionSetTag("tag1", "tagdesc1", "")); + .createDistributionSetTag(new JpaDistributionSetTag("tag1", "tagdesc1", "")); // toggle A only -> A is now assigned DistributionSetTagAssignmentResult result = distributionSetManagement.toggleTagAssignment(groupA, tag); assertThat(result.getAlreadyAssigned()).isEqualTo(0); assertThat(result.getAssigned()).isEqualTo(20); - assertThat(result.getAssignedEntity()).containsAll(distributionSetManagement.findDistributionSetListWithDetails( - groupA.stream().map(set -> set.getId()).collect(Collectors.toList()))); + assertThat(result.getAssignedEntity()).containsAll(distributionSetManagement + .findDistributionSetsAll(groupA.stream().map(set -> set.getId()).collect(Collectors.toList()))); assertThat(result.getUnassigned()).isEqualTo(0); assertThat(result.getUnassignedEntity()).isEmpty(); assertThat(result.getDistributionSetTag()).isEqualTo(tag); @@ -189,8 +182,8 @@ public class TagManagementTest extends AbstractIntegrationTest { result = distributionSetManagement.toggleTagAssignment(concat(groupA, groupB), tag); assertThat(result.getAlreadyAssigned()).isEqualTo(20); assertThat(result.getAssigned()).isEqualTo(20); - assertThat(result.getAssignedEntity()).containsAll(distributionSetManagement.findDistributionSetListWithDetails( - groupB.stream().map(set -> set.getId()).collect(Collectors.toList()))); + assertThat(result.getAssignedEntity()).containsAll(distributionSetManagement + .findDistributionSetsAll(groupB.stream().map(set -> set.getId()).collect(Collectors.toList()))); assertThat(result.getUnassigned()).isEqualTo(0); assertThat(result.getUnassignedEntity()).isEmpty(); assertThat(result.getDistributionSetTag()).isEqualTo(tag); @@ -201,7 +194,7 @@ public class TagManagementTest extends AbstractIntegrationTest { assertThat(result.getAssigned()).isEqualTo(0); assertThat(result.getAssignedEntity()).isEmpty(); assertThat(result.getUnassigned()).isEqualTo(40); - assertThat(result.getUnassignedEntity()).containsAll(distributionSetManagement.findDistributionSetListWithDetails( + assertThat(result.getUnassignedEntity()).containsAll(distributionSetManagement.findDistributionSetsAll( concat(groupB, groupA).stream().map(set -> set.getId()).collect(Collectors.toList()))); assertThat(result.getDistributionSetTag()).isEqualTo(tag); @@ -211,10 +204,10 @@ public class TagManagementTest extends AbstractIntegrationTest { @Description("Verifies the toogle mechanism by means on assigning tag if at least on target in the list does not have" + "the tag yet. Unassign if all of them have the tag already.") public void assignAndUnassignTargetTags() { - final List groupA = targetManagement.createTargets(TestDataUtil.generateTargets(20, "")); - final List groupB = targetManagement.createTargets(TestDataUtil.generateTargets(20, "groupb")); + final List groupA = targetManagement.createTargets(testdataFactory.generateTargets(20, "")); + final List groupB = targetManagement.createTargets(testdataFactory.generateTargets(20, "groupb")); - final TargetTag tag = tagManagement.createTargetTag(new TargetTag("tag1", "tagdesc1", "")); + final TargetTag tag = tagManagement.createTargetTag(new JpaTargetTag("tag1", "tagdesc1", "")); // toggle A only -> A is now assigned TargetTagAssignmentResult result = targetManagement.toggleTagAssignment(groupA, tag); @@ -249,7 +242,7 @@ public class TagManagementTest extends AbstractIntegrationTest { } @SafeVarargs - private final List concat(final List... targets) { + private final Collection concat(final Collection... targets) { final List result = new ArrayList<>(); Arrays.asList(targets).forEach(result::addAll); return result; @@ -258,16 +251,16 @@ public class TagManagementTest extends AbstractIntegrationTest { @Test @Description("Ensures that all tags are retrieved through repository.") public void findAllTargetTags() { - final List tags = createTargetsWithTags(); + final List tags = createTargetsWithTags(); - assertThat(targetTagRepository.findAll()).isEqualTo(tagManagement.findAllTargetTags()).isEqualTo(tags) + assertThat(targetTagRepository.findAll()).isEqualTo(targetTagRepository.findAll()).isEqualTo(tags) .as("Wrong tag size").hasSize(20); } @Test @Description("Ensures that a created tag is persisted in the repository as defined.") public void createTargetTag() { - final Tag tag = tagManagement.createTargetTag(new TargetTag("kai1", "kai2", "colour")); + final Tag tag = tagManagement.createTargetTag(new JpaTargetTag("kai1", "kai2", "colour")); assertThat(targetTagRepository.findByNameEquals("kai1").getDescription()).as("wrong tag ed").isEqualTo("kai2"); assertThat(tagManagement.findTargetTag("kai1").getColour()).as("wrong tag found").isEqualTo("colour"); @@ -279,7 +272,7 @@ public class TagManagementTest extends AbstractIntegrationTest { public void deleteTargetTas() { // create test data - final Iterable tags = createTargetsWithTags(); + final Iterable tags = createTargetsWithTags(); final TargetTag toDelete = tags.iterator().next(); for (final Target target : targetRepository.findAll()) { @@ -296,13 +289,13 @@ public class TagManagementTest extends AbstractIntegrationTest { .doesNotContain(toDelete); } assertThat(targetTagRepository.findOne(toDelete.getId())).as("No tag should be found").isNull(); - assertThat(tagManagement.findAllTargetTags()).as("Wrong target tag size").hasSize(19); + assertThat(targetTagRepository.findAll()).as("Wrong target tag size").hasSize(19); } @Test @Description("Tests the name update of a target tag.") public void updateTargetTag() { - final List tags = createTargetsWithTags(); + final List tags = createTargetsWithTags(); // change data final TargetTag savedAssigned = tags.iterator().next(); @@ -312,7 +305,7 @@ public class TagManagementTest extends AbstractIntegrationTest { tagManagement.updateTargetTag(savedAssigned); // check data - assertThat(tagManagement.findAllTargetTags()).as("Wrong target tag size").hasSize(tags.size()); + assertThat(targetTagRepository.findAll()).as("Wrong target tag size").hasSize(tags.size()); assertThat(targetTagRepository.findOne(savedAssigned.getId()).getName()).as("wrong target tag is saved") .isEqualTo("test123"); assertThat(targetTagRepository.findOne(savedAssigned.getId()).getOptLockRevision()) @@ -322,7 +315,7 @@ public class TagManagementTest extends AbstractIntegrationTest { @Test @Description("Ensures that a created tag is persisted in the repository as defined.") public void createDistributionSetTag() { - final Tag tag = tagManagement.createDistributionSetTag(new DistributionSetTag("kai1", "kai2", "colour")); + final Tag tag = tagManagement.createDistributionSetTag(new JpaDistributionSetTag("kai1", "kai2", "colour")); assertThat(distributionSetTagRepository.findByNameEquals("kai1").getDescription()).as("wrong tag found") .isEqualTo("kai2"); @@ -366,10 +359,10 @@ public class TagManagementTest extends AbstractIntegrationTest { @Test @Description("Ensures that a tag cannot be created if one exists already with that name (ecpects EntityAlreadyExistsException).") public void failedDuplicateTargetTagNameException() { - tagManagement.createTargetTag(new TargetTag("A")); + tagManagement.createTargetTag(new JpaTargetTag("A")); try { - tagManagement.createTargetTag(new TargetTag("A")); + tagManagement.createTargetTag(new JpaTargetTag("A")); fail("should not have worked as tag already exists"); } catch (final EntityAlreadyExistsException e) { @@ -379,8 +372,8 @@ public class TagManagementTest extends AbstractIntegrationTest { @Test @Description("Ensures that a tag cannot be updated to a name that already exists on another tag (ecpects EntityAlreadyExistsException).") public void failedDuplicateTargetTagNameExceptionAfterUpdate() { - tagManagement.createTargetTag(new TargetTag("A")); - final TargetTag tag = tagManagement.createTargetTag(new TargetTag("B")); + tagManagement.createTargetTag(new JpaTargetTag("A")); + final TargetTag tag = tagManagement.createTargetTag(new JpaTargetTag("B")); tag.setName("A"); try { @@ -394,9 +387,9 @@ public class TagManagementTest extends AbstractIntegrationTest { @Test @Description("Ensures that a tag cannot be created if one exists already with that name (ecpects EntityAlreadyExistsException).") public void failedDuplicateDsTagNameException() { - tagManagement.createDistributionSetTag(new DistributionSetTag("A")); + tagManagement.createDistributionSetTag(new JpaDistributionSetTag("A")); try { - tagManagement.createDistributionSetTag(new DistributionSetTag("A")); + tagManagement.createDistributionSetTag(new JpaDistributionSetTag("A")); fail("should not have worked as tag already exists"); } catch (final EntityAlreadyExistsException e) { @@ -406,8 +399,8 @@ public class TagManagementTest extends AbstractIntegrationTest { @Test @Description("Ensures that a tag cannot be updated to a name that already exists on another tag (ecpects EntityAlreadyExistsException).") public void failedDuplicateDsTagNameExceptionAfterUpdate() { - tagManagement.createDistributionSetTag(new DistributionSetTag("A")); - final DistributionSetTag tag = tagManagement.createDistributionSetTag(new DistributionSetTag("B")); + tagManagement.createDistributionSetTag(new JpaDistributionSetTag("A")); + final DistributionSetTag tag = tagManagement.createDistributionSetTag(new JpaDistributionSetTag("B")); tag.setName("A"); try { @@ -448,21 +441,19 @@ public class TagManagementTest extends AbstractIntegrationTest { assertThat(distributionSetTagRepository.findAll()).as("Wrong size of tags").hasSize(20); } - private List createTargetsWithTags() { - targetManagement.createTargets(TestDataUtil.generateTargets(20)); - final Iterable tags = tagManagement.createTargetTags(TestDataUtil.generateTargetTags(20)); + private List createTargetsWithTags() { + final List targets = testdataFactory.createTargets(20); + final Iterable tags = tagManagement.createTargetTags(testdataFactory.generateTargetTags(20)); - tags.forEach(tag -> targetManagement.toggleTagAssignment(targetRepository.findAll(), tag)); + tags.forEach(tag -> targetManagement.toggleTagAssignment(targets, tag)); - return tagManagement.findAllTargetTags(); + return targetTagRepository.findAll(); } private List createDsSetsWithTags() { - final List sets = TestDataUtil.generateDistributionSets(20, softwareManagement, - distributionSetManagement); - final Iterable tags = tagManagement - .createDistributionSetTags(TestDataUtil.generateDistributionSetTags(20)); + final Collection sets = testdataFactory.createDistributionSets(20); + final Iterable tags = testdataFactory.createDistributionSetTags(20); tags.forEach(tag -> distributionSetManagement.toggleTagAssignment(sets, tag)); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagenmentTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetFilterQueryManagenmentTest.java similarity index 78% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagenmentTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetFilterQueryManagenmentTest.java index 99e08f331..07b92ebeb 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagenmentTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetFilterQueryManagenmentTest.java @@ -6,13 +6,14 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; -import org.eclipse.hawkbit.AbstractIntegrationTest; +import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.junit.Test; @@ -26,14 +27,14 @@ import ru.yandex.qatools.allure.annotations.Stories; */ @Features("Component Tests - Repository") @Stories("Target Filter Query Management") -public class TargetFilterQueryManagenmentTest extends AbstractIntegrationTest { +public class TargetFilterQueryManagenmentTest extends AbstractJpaIntegrationTest { @Test @Description("Test creation of target filter query.") public void createTargetFilterQuery() { final String filterName = "new target filter"; final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement - .createTargetFilterQuery(new TargetFilterQuery(filterName, "name==PendingTargets001")); + .createTargetFilterQuery(new JpaTargetFilterQuery(filterName, "name==PendingTargets001")); assertEquals("Retrieved newly created custom target filter", targetFilterQuery, targetFilterQueryManagement.findTargetFilterQueryByName(filterName)); } @@ -43,11 +44,11 @@ public class TargetFilterQueryManagenmentTest extends AbstractIntegrationTest { public void createDuplicateTargetFilterQuery() { final String filterName = "new target filter duplicate"; targetFilterQueryManagement - .createTargetFilterQuery(new TargetFilterQuery(filterName, "name==PendingTargets001")); + .createTargetFilterQuery(new JpaTargetFilterQuery(filterName, "name==PendingTargets001")); try { targetFilterQueryManagement - .createTargetFilterQuery(new TargetFilterQuery(filterName, "name==PendingTargets001")); + .createTargetFilterQuery(new JpaTargetFilterQuery(filterName, "name==PendingTargets001")); fail("should not have worked as query already exists"); } catch (final EntityAlreadyExistsException e) { @@ -59,7 +60,7 @@ public class TargetFilterQueryManagenmentTest extends AbstractIntegrationTest { public void deleteTargetFilterQuery() { final String filterName = "delete_target_filter_query"; final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement - .createTargetFilterQuery(new TargetFilterQuery(filterName, "name==PendingTargets001")); + .createTargetFilterQuery(new JpaTargetFilterQuery(filterName, "name==PendingTargets001")); targetFilterQueryManagement.deleteTargetFilterQuery(targetFilterQuery.getId()); assertEquals("Returns null as the target filter is deleted", null, targetFilterQueryManagement.findTargetFilterQueryById(targetFilterQuery.getId())); @@ -71,7 +72,7 @@ public class TargetFilterQueryManagenmentTest extends AbstractIntegrationTest { public void updateTargetFilterQuery() { final String filterName = "target_filter_01"; final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement - .createTargetFilterQuery(new TargetFilterQuery(filterName, "name==PendingTargets001")); + .createTargetFilterQuery(new JpaTargetFilterQuery(filterName, "name==PendingTargets001")); final String newQuery = "status==UNKNOWN"; targetFilterQuery.setQuery(newQuery); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementSearchTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementSearchTest.java similarity index 82% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementSearchTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementSearchTest.java index 73d549eb7..1e8f102c7 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementSearchTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementSearchTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; @@ -17,19 +17,20 @@ import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.TestDataUtil; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.eclipse.hawkbit.repository.model.TargetIdName; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; -import org.eclipse.hawkbit.repository.specifications.TargetSpecifications; import org.junit.Test; import org.springframework.data.domain.Slice; @@ -43,44 +44,42 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("Target Management Searches") -public class TargetManagementSearchTest extends AbstractIntegrationTest { +public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { @Test @Description("Tests different parameter combinations for target search operations. " + "That includes both the test itself, as a count operation with the same filters " + "and query definitions by RSQL (named and un-named).") public void targetSearchWithVariousFilterCombinations() { - final TargetTag targTagX = tagManagement.createTargetTag(new TargetTag("TargTag-X")); - final TargetTag targTagY = tagManagement.createTargetTag(new TargetTag("TargTag-Y")); - final TargetTag targTagZ = tagManagement.createTargetTag(new TargetTag("TargTag-Z")); - final TargetTag targTagW = tagManagement.createTargetTag(new TargetTag("TargTag-W")); + final TargetTag targTagX = tagManagement.createTargetTag(new JpaTargetTag("TargTag-X")); + final TargetTag targTagY = tagManagement.createTargetTag(new JpaTargetTag("TargTag-Y")); + final TargetTag targTagZ = tagManagement.createTargetTag(new JpaTargetTag("TargTag-Z")); + final TargetTag targTagW = tagManagement.createTargetTag(new JpaTargetTag("TargTag-W")); - final DistributionSet setA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + final DistributionSet setA = testdataFactory.createDistributionSet(""); - final DistributionSet installedSet = TestDataUtil.generateDistributionSet("another", softwareManagement, - distributionSetManagement); + final DistributionSet installedSet = testdataFactory.createDistributionSet("another"); final String targetDsAIdPref = "targ-A"; List targAs = targetManagement.createTargets( - TestDataUtil.buildTargetFixtures(100, targetDsAIdPref, targetDsAIdPref.concat(" description"))); + testdataFactory.generateTargets(100, targetDsAIdPref, targetDsAIdPref.concat(" description"))); targAs = targetManagement.toggleTagAssignment(targAs, targTagX).getAssignedEntity(); final String targetDsBIdPref = "targ-B"; List targBs = targetManagement.createTargets( - TestDataUtil.buildTargetFixtures(100, targetDsBIdPref, targetDsBIdPref.concat(" description"))); + testdataFactory.generateTargets(100, targetDsBIdPref, targetDsBIdPref.concat(" description"))); targBs = targetManagement.toggleTagAssignment(targBs, targTagY).getAssignedEntity(); targBs = targetManagement.toggleTagAssignment(targBs, targTagW).getAssignedEntity(); final String targetDsCIdPref = "targ-C"; List targCs = targetManagement.createTargets( - TestDataUtil.buildTargetFixtures(100, targetDsCIdPref, targetDsCIdPref.concat(" description"))); + testdataFactory.generateTargets(100, targetDsCIdPref, targetDsCIdPref.concat(" description"))); targCs = targetManagement.toggleTagAssignment(targCs, targTagZ).getAssignedEntity(); targCs = targetManagement.toggleTagAssignment(targCs, targTagW).getAssignedEntity(); final String targetDsDIdPref = "targ-D"; final List targDs = targetManagement.createTargets( - TestDataUtil.buildTargetFixtures(100, targetDsDIdPref, targetDsDIdPref.concat(" description"))); + testdataFactory.generateTargets(100, targetDsDIdPref, targetDsDIdPref.concat(" description"))); final String assignedC = targCs.iterator().next().getControllerId(); deploymentManagement.assignDistributionSet(setA.getId(), assignedC); @@ -96,7 +95,7 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { final Action action = deploymentManagement.findActionWithDetails(actionId); action.setStatus(Status.FINISHED); controllerManagament.addUpdateActionStatus( - new ActionStatus(action, Status.FINISHED, System.currentTimeMillis(), "message"), action); + new JpaActionStatus((JpaAction) action, Status.FINISHED, System.currentTimeMillis(), "message")); deploymentManagement.assignDistributionSet(setA.getId(), installedC); final List unknown = new ArrayList<>(); @@ -174,13 +173,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, installedSet.getId(), Boolean.FALSE, new String[0])).as("has number of elements").hasSize(1) .as("and contains the following elements").containsExactly(expectedIdName) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findAllTargetIdsByTargetFilterQuery(pageReq, new TargetFilterQuery("test", query))); + .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @@ -200,13 +199,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, both, null, null, Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(200).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } private static List convertToIdNames(final List expected) { @@ -234,13 +233,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(2).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -260,13 +259,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(2).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -286,13 +285,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, "%targ-B%", setA.getId(), Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(1).as("and contains the following elements") .containsExactly(expectedIdName).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -312,13 +311,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0])).as("has number of elements").hasSize(1).as("and contains the following elements") .containsExactly(expectedIdName).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -337,13 +336,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, setA.getId(), Boolean.FALSE, new String[0])).as("has number of elements").hasSize(3).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -361,14 +360,14 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat( targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, Boolean.FALSE, new String[0])) .as("has number of elements").hasSize(3).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -388,13 +387,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, "%targ-B%", null, Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(99).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -412,13 +411,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, "%targ-A%", null, Boolean.FALSE, new String[0])).as("has number of elements").hasSize(99).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -435,12 +434,12 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .hasSize(targetManagement.findTargetsAll(query, pageReq).getContent().size()) .as("and NAMED filter query returns the same result").hasSize(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent().size()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent().size()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, setA.getId(), Boolean.FALSE, new String[0])).as("has number of elements").hasSize(0) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findAllTargetIdsByTargetFilterQuery(pageReq, new TargetFilterQuery("test", query))); + .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @Step @@ -459,13 +458,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, Boolean.FALSE, targTagY.getName(), targTagW.getName())).as("has number of elements").hasSize(198) .as("and contains the following elements").containsAll(expectedIdNames) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findAllTargetIdsByTargetFilterQuery(pageReq, new TargetFilterQuery("test", query))); + .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @Step @@ -483,14 +482,14 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat( targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, Boolean.FALSE, new String[0])) .as("has number of elements").hasSize(397).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -509,13 +508,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0])).as("has number of elements").hasSize(1).as("and contains the following elements") .containsExactly(expectedIdName).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -532,13 +531,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, setA.getId(), Boolean.FALSE, new String[0])).as("has number of elements").hasSize(3).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -554,12 +553,12 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .hasSize(targetManagement.findTargetsAll(query, pageReq).getContent().size()) .as("and NAMED filter query returns the same result").hasSize(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent().size()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent().size()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagX.getName())).as("has number of elements").hasSize(0) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findAllTargetIdsByTargetFilterQuery(pageReq, new TargetFilterQuery("test", query))); + .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @Step @@ -575,12 +574,12 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .hasSize(targetManagement.findTargetsAll(query, pageReq).getContent().size()) .as("and NAMED filter query returns the same result").hasSize(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent().size()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent().size()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-A%", setA.getId(), Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(0) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findAllTargetIdsByTargetFilterQuery(pageReq, new TargetFilterQuery("test", query))); + .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @Step @@ -599,13 +598,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(1).as("and contains the following elements") .containsExactly(expectedIdName).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @Step @@ -623,13 +622,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-B%", null, Boolean.FALSE, targTagY.getName(), targTagW.getName())).as("has number of elements").hasSize(100) .as("and contains the following elements").containsAll(expectedIdNames) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findAllTargetIdsByTargetFilterQuery(pageReq, new TargetFilterQuery("test", query))); + .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @@ -653,13 +652,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement - .findTargetsAll(new TargetFilterQuery("test", query), pageReq).getContent()); + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, null, Boolean.FALSE, targTagD.getName())).as("has number of elements").hasSize(200).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new TargetFilterQuery("test", query))); + new JpaTargetFilterQuery("test", query))); } @@ -679,14 +678,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { public void targetSearchWithVariousFilterCombinationsAndOrderByDistributionSet() { final List notAssigned = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(3, "not", "first description")); + .createTargets(testdataFactory.generateTargets(3, "not", "first description")); List targAssigned = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(3, "assigned", "first description")); + .createTargets(testdataFactory.generateTargets(3, "assigned", "first description")); List targInstalled = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(3, "installed", "first description")); + .createTargets(testdataFactory.generateTargets(3, "installed", "first description")); - final DistributionSet ds = TestDataUtil.generateDistributionSet("a", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet("a"); targAssigned = deploymentManagement.assignDistributionSet(ds, targAssigned).getAssignedEntity(); targInstalled = deploymentManagement.assignDistributionSet(ds, targInstalled).getAssignedEntity(); @@ -698,7 +696,7 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { final Comparator byId = (e1, e2) -> Long.compare(e2.getId(), e1.getId()); assertThat(result.getNumberOfElements()).isEqualTo(9); - final List expected = new ArrayList(); + final List expected = new ArrayList<>(); Collections.sort(targInstalled, byId); Collections.sort(targAssigned, byId); Collections.sort(notAssigned, byId); @@ -713,10 +711,9 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { @Test @Description("Verfies that targets with given assigned DS are returned from repository.") public void findTargetByAssignedDistributionSet() { - final DistributionSet assignedSet = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); - targetManagement.createTargets(TestDataUtil.generateTargets(10, "unassigned")); - List assignedtargets = targetManagement.createTargets(TestDataUtil.generateTargets(10, "assigned")); + final DistributionSet assignedSet = testdataFactory.createDistributionSet(""); + targetManagement.createTargets(testdataFactory.generateTargets(10, "unassigned")); + List assignedtargets = targetManagement.createTargets(testdataFactory.generateTargets(10, "assigned")); deploymentManagement.assignDistributionSet(assignedSet, assignedtargets); @@ -730,50 +727,20 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { } - @Test - @Description("Verfies that targets with given assigned DS and additonal specification are returned from repository.") - public void findTargetByAssignedDistributionSetWithAdditonalSpecification() { - final DistributionSet assignedSet = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); - final DistributionSet installedSet = TestDataUtil.generateDistributionSet("another", softwareManagement, - distributionSetManagement); - targetManagement.createTargets(TestDataUtil.generateTargets(10, "unassigned")); - List assignedtargets = targetManagement.createTargets(TestDataUtil.generateTargets(10, "assigned")); - - // set on installed and assign another one - deploymentManagement.assignDistributionSet(installedSet, assignedtargets).getActions().forEach(actionId -> { - final Action action = deploymentManagement.findActionWithDetails(actionId); - action.setStatus(Status.FINISHED); - controllerManagament.addUpdateActionStatus( - new ActionStatus(action, Status.FINISHED, System.currentTimeMillis(), "message"), action); - }); - deploymentManagement.assignDistributionSet(assignedSet, assignedtargets); - - assignedtargets = targetManagement.findTargetByControllerID( - assignedtargets.stream().map(target -> target.getControllerId()).collect(Collectors.toList())); - - assertThat(targetManagement.findTargetByAssignedDistributionSet(assignedSet.getId(), - TargetSpecifications.hasInstalledDistributionSet(installedSet.getId()), pageReq)) - .as("Contains the assigned targets").containsAll(assignedtargets) - .as("and that means the following expected amount").hasSize(10); - } - @Test @Description("Verfies that targets with given installed DS are returned from repository.") public void findTargetByInstalledDistributionSet() { - final DistributionSet assignedSet = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); - final DistributionSet installedSet = TestDataUtil.generateDistributionSet("another", softwareManagement, - distributionSetManagement); - targetManagement.createTargets(TestDataUtil.generateTargets(10, "unassigned")); - List installedtargets = targetManagement.createTargets(TestDataUtil.generateTargets(10, "assigned")); + final DistributionSet assignedSet = testdataFactory.createDistributionSet(""); + final DistributionSet installedSet = testdataFactory.createDistributionSet("another"); + targetManagement.createTargets(testdataFactory.generateTargets(10, "unassigned")); + List installedtargets = targetManagement.createTargets(testdataFactory.generateTargets(10, "assigned")); // set on installed and assign another one deploymentManagement.assignDistributionSet(installedSet, installedtargets).getActions().forEach(actionId -> { final Action action = deploymentManagement.findActionWithDetails(actionId); action.setStatus(Status.FINISHED); controllerManagament.addUpdateActionStatus( - new ActionStatus(action, Status.FINISHED, System.currentTimeMillis(), "message"), action); + new JpaActionStatus((JpaAction) action, Status.FINISHED, System.currentTimeMillis(), "message")); }); deploymentManagement.assignDistributionSet(assignedSet, installedtargets); @@ -787,41 +754,11 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { } - @Test - @Description("Verfies that targets with given installed DS and additonal specification are returned from repository.") - public void findTargetByInstalledDistributionSetWithAdditonalSpecification() { - final DistributionSet assignedSet = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); - final DistributionSet installedSet = TestDataUtil.generateDistributionSet("another", softwareManagement, - distributionSetManagement); - targetManagement.createTargets(TestDataUtil.generateTargets(10, "unassigned")); - List installedtargets = targetManagement.createTargets(TestDataUtil.generateTargets(10, "assigned")); - - // set on installed and assign another one - deploymentManagement.assignDistributionSet(installedSet, installedtargets).getActions().forEach(actionId -> { - final Action action = deploymentManagement.findActionWithDetails(actionId); - action.setStatus(Status.FINISHED); - controllerManagament.addUpdateActionStatus( - new ActionStatus(action, Status.FINISHED, System.currentTimeMillis(), "message"), action); - }); - deploymentManagement.assignDistributionSet(assignedSet, installedtargets); - - // get final updated version of targets - installedtargets = targetManagement.findTargetByControllerID( - installedtargets.stream().map(target -> target.getControllerId()).collect(Collectors.toList())); - - assertThat(targetManagement.findTargetByInstalledDistributionSet(installedSet.getId(), - TargetSpecifications.hasAssignedDistributionSet(assignedSet.getId()), pageReq)) - .as("Contains the assigned targets").containsAll(installedtargets) - .as("and that means the following expected amount").hasSize(10); - - } - private List sendUpdateActionStatusToTargets(final DistributionSet dsA, final Iterable targs, final Status status, final String... msgs) { final List result = new ArrayList(); for (final Target t : targs) { - final List findByTarget = actionRepository.findByTarget(t); + final List findByTarget = actionRepository.findByTarget((JpaTarget) t); for (final Action action : findByTarget) { result.add(sendUpdateActionStatusToTarget(status, action, t, msgs)); } @@ -833,14 +770,14 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest { final String... msgs) { updActA.setStatus(status); - final ActionStatus statusMessages = new ActionStatus(); + final ActionStatus statusMessages = new JpaActionStatus(); statusMessages.setAction(updActA); statusMessages.setOccurredAt(System.currentTimeMillis()); statusMessages.setStatus(status); for (final String msg : msgs) { statusMessages.addMessage(msg); } - controllerManagament.addUpdateActionStatus(statusMessages, updActA); + controllerManagament.addUpdateActionStatus(statusMessages); return targetManagement.findTargetByControllerID(t.getControllerId()); } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java similarity index 85% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java index 1c039c8c8..06f853db6 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; @@ -28,22 +28,23 @@ import java.util.stream.Collectors; import javax.persistence.Query; 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.im.authentication.SpPermission; +import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.TenantNotExistException; -import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Tag; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetIdName; -import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetTag; +import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.Test; import org.springframework.data.domain.PageRequest; @@ -55,12 +56,12 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("Target Management") -public class TargetManagementTest extends AbstractIntegrationTest { +public class TargetManagementTest extends AbstractJpaIntegrationTest { @Test @Description("Ensures that retrieving the target security is only permitted with the necessary permissions.") public void getTargetSecurityTokenOnlyWithCorrectPermission() throws Exception { - final Target createdTarget = targetManagement.createTarget(new Target("targetWithSecurityToken")); + final Target createdTarget = targetManagement.createTarget(new JpaTarget("targetWithSecurityToken", "token")); // retrieve security token only with READ_TARGET_SEC_TOKEN permission final String securityTokenWithReadPermission = securityRule.runAs(WithSpringAuthorityRule @@ -79,7 +80,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { return createdTarget.getSecurityToken(); }); - assertThat(createdTarget.getSecurityToken()).isNotNull(); + assertThat(createdTarget.getSecurityToken()).isEqualTo("token"); assertThat(securityTokenWithReadPermission).isNotNull(); assertThat(securityTokenAsSystemCode).isNotNull(); @@ -92,7 +93,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { @WithUser(tenantId = "tenantWhichDoesNotExists", allSpPermissions = true, autoCreateTenant = false) public void createTargetForTenantWhichDoesNotExistThrowsTenantNotExistException() { try { - targetManagement.createTarget(new Target("targetId123")); + targetManagement.createTarget(new JpaTarget("targetId123")); fail("should not be possible as the tenant does not exist"); } catch (final TenantNotExistException e) { // ok @@ -103,14 +104,14 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Description("Verify that a target with empty controller id cannot be created") public void createTargetWithNoControllerId() { try { - targetManagement.createTarget(new Target("")); + targetManagement.createTarget(new JpaTarget("")); fail("target with empty controller id should not be created"); } catch (final ConstraintViolationException e) { // ok } try { - targetManagement.createTarget(new Target(null)); + targetManagement.createTarget(new JpaTarget(null)); fail("target with empty controller id should not be created"); } catch (final ConstraintViolationException e) { // ok @@ -121,13 +122,13 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Description("Ensures that targets can assigned and unassigned to a target tag. Not exists target will be ignored for the assignment.") public void assignAndUnassignTargetsToTag() { final List assignTarget = new ArrayList(); - assignTarget.add(targetManagement.createTarget(new Target("targetId123")).getControllerId()); - assignTarget.add(targetManagement.createTarget(new Target("targetId1234")).getControllerId()); - assignTarget.add(targetManagement.createTarget(new Target("targetId1235")).getControllerId()); - assignTarget.add(targetManagement.createTarget(new Target("targetId1236")).getControllerId()); + assignTarget.add(targetManagement.createTarget(new JpaTarget("targetId123")).getControllerId()); + assignTarget.add(targetManagement.createTarget(new JpaTarget("targetId1234")).getControllerId()); + assignTarget.add(targetManagement.createTarget(new JpaTarget("targetId1235")).getControllerId()); + assignTarget.add(targetManagement.createTarget(new JpaTarget("targetId1236")).getControllerId()); assignTarget.add("NotExist"); - final TargetTag targetTag = tagManagement.createTargetTag(new TargetTag("Tag1")); + final TargetTag targetTag = tagManagement.createTargetTag(new JpaTargetTag("Tag1")); final List assignedTargets = targetManagement.assignTag(assignTarget, targetTag); assertThat(assignedTargets.size()).as("Assigned targets are wrong").isEqualTo(4); @@ -156,7 +157,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Test @Description("Ensures that targets can deleted e.g. test all cascades") public void deleteAndCreateTargets() { - Target target = targetManagement.createTarget(new Target("targetId123")); + Target target = targetManagement.createTarget(new JpaTarget("targetId123")); assertThat(targetManagement.countTargetsAll()).as("target count is wrong").isEqualTo(1); targetManagement.deleteTargets(target.getId()); assertThat(targetManagement.countTargetsAll()).as("target count is wrong").isEqualTo(0); @@ -168,7 +169,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { final List targets = new ArrayList(); for (int i = 0; i < 5; i++) { - target = targetManagement.createTarget(new Target("" + i)); + target = targetManagement.createTarget(new JpaTarget("" + i)); targets.add(target.getId()); targets.add(createTargetWithAttributes("" + (i * i + 1000)).getId()); } @@ -178,7 +179,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { } private Target createTargetWithAttributes(final String controllerId) { - Target target = new Target(controllerId); + Target target = new JpaTarget(controllerId); final Map testData = new HashMap<>(); testData.put("test1", "testdata1"); @@ -194,10 +195,8 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Test @Description("Finds a target by given ID and checks if all data is in the reponse (including the data defined as lazy).") public void findTargetByControllerIDWithDetails() { - final DistributionSet set = TestDataUtil.generateDistributionSet("test", softwareManagement, - distributionSetManagement); - final DistributionSet set2 = TestDataUtil.generateDistributionSet("test2", softwareManagement, - distributionSetManagement); + final DistributionSet set = testdataFactory.createDistributionSet("test"); + final DistributionSet set2 = testdataFactory.createDistributionSet("test2"); assertThat(targetManagement.countTargetByAssignedDistributionSet(set.getId())).as("Target count is wrong") .isEqualTo(0); @@ -215,10 +214,10 @@ public class TargetManagementTest extends AbstractIntegrationTest { final DistributionSetAssignmentResult result = deploymentManagement.assignDistributionSet(set.getId(), "4711"); - final Action action = deploymentManagement.findActionWithDetails(result.getActions().get(0)); + final JpaAction action = (JpaAction) deploymentManagement.findActionWithDetails(result.getActions().get(0)); action.setStatus(Status.FINISHED); controllerManagament.addUpdateActionStatus( - new ActionStatus(action, Status.FINISHED, System.currentTimeMillis(), "message"), action); + new JpaActionStatus(action, Status.FINISHED, System.currentTimeMillis(), "message")); deploymentManagement.assignDistributionSet(set2.getId(), "4711"); target = targetManagement.findTargetByControllerIDWithDetails("4711"); @@ -249,7 +248,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Test @Description("Checks if the EntityAlreadyExistsException is thrown if the targets with the same controller ID are created twice.") public void createMultipleTargetsDuplicate() { - final List targets = TestDataUtil.buildTargetFixtures(5, "mySimpleTargs", "my simple targets"); + final List targets = testdataFactory.generateTargets(5, "mySimpleTargs", "my simple targets"); targetManagement.createTargets(targets); try { targetManagement.createTargets(targets); @@ -262,9 +261,9 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Test @Description("Checks if the EntityAlreadyExistsException is thrown if a single target with the same controller ID are created twice.") public void createTargetDuplicate() { - targetManagement.createTarget(new Target("4711")); + targetManagement.createTarget(new JpaTarget("4711")); try { - targetManagement.createTarget(new Target("4711")); + targetManagement.createTarget(new JpaTarget("4711")); fail("Target already exists"); } catch (final EntityAlreadyExistsException e) { } @@ -324,7 +323,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { public void singleTargetIsInsertedIntoRepo() throws Exception { final String myCtrlID = "myCtrlID"; - final Target target = TestDataUtil.buildTargetFixture(myCtrlID, "the description!"); + final Target target = testdataFactory.generateTarget(myCtrlID, "the description!"); Target savedTarget = targetManagement.createTarget(target); assertNotNull("The target should not be null", savedTarget); @@ -361,15 +360,15 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Description("Create multiple tragets as bulk operation and delete them in bulk.") public void bulkTargetCreationAndDelete() throws Exception { final String myCtrlID = "myCtrlID"; - final List firstList = TestDataUtil.buildTargetFixtures(100, myCtrlID, "first description"); + final List firstList = testdataFactory.generateTargets(100, myCtrlID, "first description"); - final Target extra = TestDataUtil.buildTargetFixture("myCtrlID-00081XX", "first description"); + final Target extra = testdataFactory.generateTarget("myCtrlID-00081XX", "first description"); List firstSaved = targetManagement.createTargets(firstList); final Target savedExtra = targetManagement.createTarget(extra); - Iterable allFound = targetRepository.findAll(); + final Iterable allFound = targetRepository.findAll(); assertThat(Long.valueOf(firstList.size())).as("List size of targets") .isEqualTo(firstSaved.spliterator().getExactSizeIfKnown()); @@ -422,31 +421,31 @@ public class TargetManagementTest extends AbstractIntegrationTest { targetManagement.deleteTargets(deletedTargetIDs); - allFound = targetManagement.findTargetsAll(new PageRequest(0, 200)).getContent(); + final List found = targetManagement.findTargetsAll(new PageRequest(0, 200)).getContent(); assertThat(firstSaved.spliterator().getExactSizeIfKnown() - nr2Del).as("Size of splited list") - .isEqualTo(allFound.spliterator().getExactSizeIfKnown()); + .isEqualTo(found.spliterator().getExactSizeIfKnown()); - assertThat(allFound).as("Not all undeleted found").doesNotContain(deletedTargets); + assertThat(found).as("Not all undeleted found").doesNotContain(deletedTargets); } @Test @Description("Stores target attributes and verfies existence in the repository.") public void savingTargetControllerAttributes() { Iterable ts = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(100, "myCtrlID", "first description")); + .createTargets(testdataFactory.generateTargets(100, "myCtrlID", "first description")); - final Map attribs = new HashMap(); + final Map attribs = new HashMap<>(); attribs.put("a.b.c", "abc"); attribs.put("x.y.z", ""); attribs.put("1.2.3", "123"); attribs.put("1.2.3.4", "1234"); attribs.put("1.2.3.4.5", "12345"); - final Set attribs2Del = new HashSet(); + final Set attribs2Del = new HashSet<>(); attribs2Del.add("x.y.z"); attribs2Del.add("1.2.3"); for (final Target t : ts) { - TargetInfo targetInfo = t.getTargetInfo(); + JpaTargetInfo targetInfo = (JpaTargetInfo) t.getTargetInfo(); targetInfo.setNew(false); for (final Entry attrib : attribs.entrySet()) { final String key = attrib.getKey(); @@ -491,7 +490,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { for (final Target ta : ts2DelAllAttribs) { final Target t = targetManagement.findTargetByControllerIDWithDetails(ta.getControllerId()); - final TargetInfo targetStatus = t.getTargetInfo(); + final JpaTargetInfo targetStatus = (JpaTargetInfo) t.getTargetInfo(); targetStatus.getControllerAttributes().clear(); targetInfoRepository.save(targetStatus); } @@ -499,7 +498,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { for (final Target ta : ts2DelAttribs) { final Target t = targetManagement.findTargetByControllerIDWithDetails(ta.getControllerId()); - final TargetInfo targetStatus = t.getTargetInfo(); + final JpaTargetInfo targetStatus = (JpaTargetInfo) t.getTargetInfo(); for (final String attribKey : attribs2Del) { targetStatus.getControllerAttributes().remove(attribKey); } @@ -508,7 +507,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { // only the number of the remaining targets and controller attributes // are checked - final Iterable restTS = targetRepository.findAll(); + final Iterable restTS = targetRepository.findAll(); restTarget_: for (final Target targetl : restTS) { final Target target = targetManagement.findTargetByControllerIDWithDetails(targetl.getControllerId()); @@ -542,17 +541,17 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Test @Description("Tests the assigment of tags to the a single target.") public void targetTagAssignment() { - Target t1 = TestDataUtil.buildTargetFixture("id-1", "blablub"); + Target t1 = testdataFactory.generateTarget("id-1", "blablub"); final int noT2Tags = 4; final int noT1Tags = 3; final List t1Tags = tagManagement - .createTargetTags(TestDataUtil.buildTargetTagFixtures(noT1Tags, "tag1")); + .createTargetTags(testdataFactory.generateTargetTags(noT1Tags, "tag1")); t1.getTags().addAll(t1Tags); t1 = targetManagement.createTarget(t1); - Target t2 = TestDataUtil.buildTargetFixture("id-2", "blablub"); + Target t2 = testdataFactory.generateTarget("id-2", "blablub"); final List t2Tags = tagManagement - .createTargetTags(TestDataUtil.buildTargetTagFixtures(noT2Tags, "tag2")); + .createTargetTags(testdataFactory.generateTargetTags(noT2Tags, "tag2")); t2.getTags().addAll(t2Tags); t2 = targetManagement.createTarget(t2); @@ -571,22 +570,22 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Description("Tests the assigment of tags to multiple targets.") public void targetTagBulkAssignments() { final List tagATargets = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(10, "tagATargets", "first description")); + .createTargets(testdataFactory.generateTargets(10, "tagATargets", "first description")); final List tagBTargets = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(10, "tagBTargets", "first description")); + .createTargets(testdataFactory.generateTargets(10, "tagBTargets", "first description")); final List tagCTargets = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(10, "tagCTargets", "first description")); + .createTargets(testdataFactory.generateTargets(10, "tagCTargets", "first description")); final List tagABTargets = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(10, "tagABTargets", "first description")); + .createTargets(testdataFactory.generateTargets(10, "tagABTargets", "first description")); final List tagABCTargets = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(10, "tagABCTargets", "first description")); + .createTargets(testdataFactory.generateTargets(10, "tagABCTargets", "first description")); - final TargetTag tagA = tagManagement.createTargetTag(new TargetTag("A")); - final TargetTag tagB = tagManagement.createTargetTag(new TargetTag("B")); - final TargetTag tagC = tagManagement.createTargetTag(new TargetTag("C")); - tagManagement.createTargetTag(new TargetTag("X")); + final TargetTag tagA = tagManagement.createTargetTag(new JpaTargetTag("A")); + final TargetTag tagB = tagManagement.createTargetTag(new JpaTargetTag("B")); + final TargetTag tagC = tagManagement.createTargetTag(new JpaTargetTag("C")); + tagManagement.createTargetTag(new JpaTargetTag("X")); // doing different assignments targetManagement.toggleTagAssignment(tagATargets, tagA); @@ -641,25 +640,25 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Test @Description("Tests the unassigment of tags to multiple targets.") public void targetTagBulkUnassignments() { - final TargetTag targTagA = tagManagement.createTargetTag(new TargetTag("Targ-A-Tag")); - final TargetTag targTagB = tagManagement.createTargetTag(new TargetTag("Targ-B-Tag")); - final TargetTag targTagC = tagManagement.createTargetTag(new TargetTag("Targ-C-Tag")); + final TargetTag targTagA = tagManagement.createTargetTag(new JpaTargetTag("Targ-A-Tag")); + final TargetTag targTagB = tagManagement.createTargetTag(new JpaTargetTag("Targ-B-Tag")); + final TargetTag targTagC = tagManagement.createTargetTag(new JpaTargetTag("Targ-C-Tag")); final List targAs = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(25, "target-id-A", "first description")); + .createTargets(testdataFactory.generateTargets(25, "target-id-A", "first description")); final List targBs = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(20, "target-id-B", "first description")); + .createTargets(testdataFactory.generateTargets(20, "target-id-B", "first description")); final List targCs = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(15, "target-id-C", "first description")); + .createTargets(testdataFactory.generateTargets(15, "target-id-C", "first description")); final List targABs = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(12, "target-id-AB", "first description")); + .createTargets(testdataFactory.generateTargets(12, "target-id-AB", "first description")); final List targACs = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(13, "target-id-AC", "first description")); + .createTargets(testdataFactory.generateTargets(13, "target-id-AC", "first description")); final List targBCs = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(7, "target-id-BC", "first description")); + .createTargets(testdataFactory.generateTargets(7, "target-id-BC", "first description")); final List targABCs = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(17, "target-id-ABC", "first description")); + .createTargets(testdataFactory.generateTargets(17, "target-id-ABC", "first description")); targetManagement.toggleTagAssignment(targAs, targTagA); targetManagement.toggleTagAssignment(targABs, targTagA); @@ -704,10 +703,10 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Test @Description("Retrieves targets by ID with lazy loading of the tags. Checks the successfull load.") public void findTargetsByControllerIDsWithTags() { - final TargetTag targTagA = tagManagement.createTargetTag(new TargetTag("Targ-A-Tag")); + final TargetTag targTagA = tagManagement.createTargetTag(new JpaTargetTag("Targ-A-Tag")); final List targAs = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(25, "target-id-A", "first description")); + .createTargets(testdataFactory.generateTargets(25, "target-id-A", "first description")); targetManagement.toggleTagAssignment(targAs, targTagA); @@ -727,7 +726,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Description("Test the optimized quere for retrieving all ID/name pairs of targets.") public void findAllTargetIdNamePaiss() { final List targAs = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(25, "target-id-A", "first description")); + .createTargets(testdataFactory.generateTargets(25, "target-id-A", "first description")); final String[] createdTargetIds = targAs.stream().map(t -> t.getControllerId()) .toArray(size -> new String[size]); @@ -742,12 +741,12 @@ public class TargetManagementTest extends AbstractIntegrationTest { @Description("Test that NO TAG functionality which gives all targets with no tag assigned.") public void findTargetsWithNoTag() { - final TargetTag targTagA = tagManagement.createTargetTag(new TargetTag("Targ-A-Tag")); + final TargetTag targTagA = tagManagement.createTargetTag(new JpaTargetTag("Targ-A-Tag")); final List targAs = targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(25, "target-id-A", "first description")); + .createTargets(testdataFactory.generateTargets(25, "target-id-A", "first description")); targetManagement.toggleTagAssignment(targAs, targTagA); - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(25, "target-id-B", "first description")); + targetManagement.createTargets(testdataFactory.generateTargets(25, "target-id-B", "first description")); final String[] tagNames = null; final List targetsListWithNoTag = targetManagement diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TenantConfigurationManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TenantConfigurationManagementTest.java similarity index 98% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TenantConfigurationManagementTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TenantConfigurationManagementTest.java index 1427df25b..73feda1c2 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TenantConfigurationManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TenantConfigurationManagementTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository; +package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.fail; @@ -16,7 +16,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; @@ -30,7 +29,7 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("Tenant Configuration Management") -public class TenantConfigurationManagementTest extends AbstractIntegrationTestWithMongoDB { +public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTestWithMongoDB { @Test @Description("Tests that tenant specific configuration can be persisted and in case the tenant does not have specific configuration the default from environment is used instead.") diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/cache/CacheKeysTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/cache/CacheKeysTest.java similarity index 95% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/cache/CacheKeysTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/cache/CacheKeysTest.java index b0da78abd..921d1953a 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/cache/CacheKeysTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/cache/CacheKeysTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.cache; +package org.eclipse.hawkbit.repository.jpa.cache; import static org.fest.assertions.api.Assertions.assertThat; diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/cache/CacheWriteNotifyTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/cache/CacheWriteNotifyTest.java similarity index 79% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/cache/CacheWriteNotifyTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/cache/CacheWriteNotifyTest.java index c88a3e717..1f6fbca6f 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/cache/CacheWriteNotifyTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/cache/CacheWriteNotifyTest.java @@ -6,15 +6,15 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.cache; +package org.eclipse.hawkbit.repository.jpa.cache; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent; -import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent; +import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.tenancy.TenantAware; import org.junit.Before; import org.junit.Test; @@ -59,15 +59,14 @@ public class CacheWriteNotifyTest { @Test public void downloadgProgressIsCachedAndEventSent() { final long knownStatusId = 1; - final int knownPercentage = 23; - when(cacheManagerMock.getCache(Action.class.getName())).thenReturn(cacheMock); + when(cacheManagerMock.getCache(ActionStatus.class.getName())).thenReturn(cacheMock); when(tenantAwareMock.getCurrentTenant()).thenReturn("default"); - underTest.downloadProgressPercent(knownStatusId, knownPercentage); + underTest.downloadProgress(knownStatusId, 500L, 100L, 100L); - verify(cacheManagerMock).getCache(eq(Action.class.getName())); - verify(cacheMock).put(knownStatusId + "." + CacheKeys.DOWNLOAD_PROGRESS_PERCENT, knownPercentage); + verify(cacheManagerMock).getCache(eq(ActionStatus.class.getName())); + verify(cacheMock).put(knownStatusId + "." + CacheKeys.DOWNLOAD_PROGRESS_PERCENT, 20); verify(eventBusMock).post(any(DownloadProgressEvent.class)); } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/eventbus/CacheFieldEntityListenerTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/eventbus/CacheFieldEntityListenerTest.java similarity index 92% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/eventbus/CacheFieldEntityListenerTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/eventbus/CacheFieldEntityListenerTest.java index 4943ea88a..3479ed232 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/eventbus/CacheFieldEntityListenerTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/eventbus/CacheFieldEntityListenerTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.eventbus; +package org.eclipse.hawkbit.repository.jpa.eventbus; import static org.fest.assertions.api.Assertions.assertThat; import static org.mockito.Matchers.anyString; @@ -14,9 +14,10 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.eclipse.hawkbit.cache.CacheField; -import org.eclipse.hawkbit.cache.CacheKeys; -import org.eclipse.hawkbit.repository.model.helper.CacheManagerHolder; +import org.eclipse.hawkbit.repository.jpa.cache.CacheField; +import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys; +import org.eclipse.hawkbit.repository.jpa.model.CacheFieldEntityListener; +import org.eclipse.hawkbit.repository.jpa.model.helper.CacheManagerHolder; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/model/ModelEqualsHashcodeTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/model/ModelEqualsHashcodeTest.java similarity index 65% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/model/ModelEqualsHashcodeTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/model/ModelEqualsHashcodeTest.java index 45e56167a..9f4cefa5d 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/model/ModelEqualsHashcodeTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/model/ModelEqualsHashcodeTest.java @@ -6,11 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.repository.jpa.model; import static org.fest.assertions.api.Assertions.assertThat; -import org.eclipse.hawkbit.AbstractIntegrationTest; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.junit.Test; import ru.yandex.qatools.allure.annotations.Description; @@ -19,35 +20,35 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Unit Tests - Repository") @Stories("Repository Model") -public class ModelEqualsHashcodeTest extends AbstractIntegrationTest { +public class ModelEqualsHashcodeTest extends AbstractJpaIntegrationTest { @Test @Description("Verfies that different objects even with identical primary key, version and tenant " + "return different hash codes.") public void differentEntitiesReturnDifferentHashCodes() { - assertThat(new Action().hashCode()).as("action should have different hashcode than action status") - .isNotEqualTo(new ActionStatus().hashCode()); - assertThat(new DistributionSet().hashCode()) + assertThat(new JpaAction().hashCode()).as("action should have different hashcode than action status") + .isNotEqualTo(new JpaActionStatus().hashCode()); + assertThat(new JpaDistributionSet().hashCode()) .as("Distribution set should have different hashcode than software module") - .isNotEqualTo(new SoftwareModule().hashCode()); - assertThat(new DistributionSet().hashCode()) + .isNotEqualTo(new JpaSoftwareModule().hashCode()); + assertThat(new JpaDistributionSet().hashCode()) .as("Distribution set should have different hashcode than action status") - .isNotEqualTo(new ActionStatus().hashCode()); - assertThat(new DistributionSetType().hashCode()) + .isNotEqualTo(new JpaActionStatus().hashCode()); + assertThat(new JpaDistributionSetType().hashCode()) .as("Distribution set type should have different hashcode than action status") - .isNotEqualTo(new ActionStatus().hashCode()); + .isNotEqualTo(new JpaActionStatus().hashCode()); } @Test @Description("Verfies that different object even with identical primary key, version and tenant " + "are not equal.") public void differentEntitiesAreNotEqual() { - assertThat(new Action().equals(new ActionStatus())).as("action equals action status").isFalse(); - assertThat(new DistributionSet().equals(new SoftwareModule())).as("Distribution set equals software module") + assertThat(new JpaAction().equals(new JpaActionStatus())).as("action equals action status").isFalse(); + assertThat(new JpaDistributionSet().equals(new JpaSoftwareModule())) + .as("Distribution set equals software module").isFalse(); + assertThat(new JpaDistributionSet().equals(new JpaActionStatus())).as("Distribution set equals action status") .isFalse(); - assertThat(new DistributionSet().equals(new ActionStatus())).as("Distribution set equals action status") - .isFalse(); - assertThat(new DistributionSetType().equals(new ActionStatus())) + assertThat(new JpaDistributionSetType().equals(new JpaActionStatus())) .as("Distribution set type equals action status").isFalse(); } @@ -55,9 +56,9 @@ public class ModelEqualsHashcodeTest extends AbstractIntegrationTest { @Description("Verfies that updated entities are not equal.") public void changedEntitiesAreNotEqual() { final SoftwareModuleType type = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test", "test", "test", 1)); + .createSoftwareModuleType(new JpaSoftwareModuleType("test", "test", "test", 1)); assertThat(type).as("persited entity is not equal to regular object") - .isNotEqualTo(new SoftwareModuleType("test", "test", "test", 1)); + .isNotEqualTo(new JpaSoftwareModuleType("test", "test", "test", 1)); type.setDescription("another"); final SoftwareModuleType updated = softwareManagement.updateSoftwareModuleType(type); @@ -68,9 +69,9 @@ public class ModelEqualsHashcodeTest extends AbstractIntegrationTest { @Description("Verify that no proxy of the entity manager has an influence on the equals or hashcode result.") public void managedEntityIsEqualToUnamangedObjectWithSameKey() { final SoftwareModuleType type = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test", "test", "test", 1)); + .createSoftwareModuleType(new JpaSoftwareModuleType("test", "test", "test", 1)); - final SoftwareModuleType mock = new SoftwareModuleType("test", "test", "test", 1); + final JpaSoftwareModuleType mock = new JpaSoftwareModuleType("test", "test", "test", 1); mock.setId(type.getId()); mock.setOptLockRevision(type.getOptLockRevision()); mock.setTenant(type.getTenant()); @@ -84,9 +85,9 @@ public class ModelEqualsHashcodeTest extends AbstractIntegrationTest { @Description("Verfies that updated entities do not have the same hashcode.") public void updatedEntitiesHaveDifferentHashcodes() { final SoftwareModuleType type = softwareManagement - .createSoftwareModuleType(new SoftwareModuleType("test", "test", "test", 1)); + .createSoftwareModuleType(new JpaSoftwareModuleType("test", "test", "test", 1)); assertThat(type.hashCode()).as("persited entity does not have same hashcode as regular object") - .isNotEqualTo(new SoftwareModuleType("test", "test", "test", 1).hashCode()); + .isNotEqualTo(new JpaSoftwareModuleType("test", "test", "test", 1).hashCode()); final int beforeChange = type.hashCode(); type.setDescription("another"); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLActionFieldsTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLActionFieldsTest.java similarity index 82% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLActionFieldsTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLActionFieldsTest.java index 8b20af27d..3138c9f86 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLActionFieldsTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLActionFieldsTest.java @@ -6,13 +6,16 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.fail; -import org.eclipse.hawkbit.AbstractIntegrationTest; import org.eclipse.hawkbit.repository.ActionFields; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Target; @@ -20,7 +23,6 @@ import org.junit.Before; import org.junit.Test; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Slice; -import org.springframework.data.jpa.domain.Specification; import ru.yandex.qatools.allure.annotations.Description; import ru.yandex.qatools.allure.annotations.Features; @@ -28,23 +30,23 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("RSQL filter actions") -public class RSQLActionFieldsTest extends AbstractIntegrationTest { +public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest { private Target target; - private Action action; + private JpaAction action; @Before public void setupBeforeTest() { - target = new Target("targetId123"); + target = new JpaTarget("targetId123"); target.setDescription("targetId123"); targetManagement.createTarget(target); - action = new Action(); + action = new JpaAction(); action.setActionType(ActionType.SOFT); target.getActions().add(action); action.setTarget(target); actionRepository.save(action); for (int i = 0; i < 10; i++) { - final Action newAction = new Action(); + final JpaAction newAction = new JpaAction(); newAction.setActionType(ActionType.SOFT); newAction.setActive(i % 2 == 0); newAction.setTarget(target); @@ -79,10 +81,9 @@ public class RSQLActionFieldsTest extends AbstractIntegrationTest { private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) { - final Specification parse = RSQLUtility.parse(rsqlParam, ActionFields.class); - final Slice findEnitity = deploymentManagement.findActionsByTarget(parse, target, + final Slice findEnitity = deploymentManagement.findActionsByTarget(rsqlParam, target, new PageRequest(0, 100)); - final long countAllEntities = deploymentManagement.countActionsByTarget(parse, target); + final long countAllEntities = deploymentManagement.countActionsByTarget(rsqlParam, target); assertThat(findEnitity).isNotNull(); assertThat(countAllEntities).isEqualTo(expectedEntities); } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetFieldTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLDistributionSetFieldTest.java similarity index 75% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetFieldTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLDistributionSetFieldTest.java index 6b1682820..4eb15a78d 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetFieldTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLDistributionSetFieldTest.java @@ -6,19 +6,21 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.fail; import java.util.Arrays; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.repository.DistributionSetFields; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.junit.Before; import org.junit.Test; import org.springframework.data.domain.Page; @@ -30,28 +32,28 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("RSQL filter distribution set") -public class RSQLDistributionSetFieldTest extends AbstractIntegrationTest { +public class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest { @Before public void seuptBeforeTest() { - DistributionSet ds = TestDataUtil.generateDistributionSet("DS", softwareManagement, distributionSetManagement); + DistributionSet ds = testdataFactory.createDistributionSet("DS"); ds.setDescription("DS"); ds = distributionSetManagement.updateDistributionSet(ds); distributionSetManagement - .createDistributionSetMetadata(new DistributionSetMetadata("metaKey", ds, "metaValue")); + .createDistributionSetMetadata(new JpaDistributionSetMetadata("metaKey", ds, "metaValue")); - DistributionSet ds2 = TestDataUtil - .generateDistributionSets("NewDS", 3, softwareManagement, distributionSetManagement).get(0); + DistributionSet ds2 = testdataFactory.createDistributionSets("NewDS", 3).get(0); ds2.setDescription("DS%"); ds2 = distributionSetManagement.updateDistributionSet(ds2); - distributionSetManagement.createDistributionSetMetadata(new DistributionSetMetadata("metaKey", ds2, "value")); + distributionSetManagement + .createDistributionSetMetadata(new JpaDistributionSetMetadata("metaKey", ds2, "value")); - final DistributionSetTag targetTag = tagManagement.createDistributionSetTag(new DistributionSetTag("Tag1")); - tagManagement.createDistributionSetTag(new DistributionSetTag("Tag2")); - tagManagement.createDistributionSetTag(new DistributionSetTag("Tag3")); - tagManagement.createDistributionSetTag(new DistributionSetTag("Tag4")); + final DistributionSetTag targetTag = tagManagement.createDistributionSetTag(new JpaDistributionSetTag("Tag1")); + tagManagement.createDistributionSetTag(new JpaDistributionSetTag("Tag2")); + tagManagement.createDistributionSetTag(new JpaDistributionSetTag("Tag3")); + tagManagement.createDistributionSetTag(new JpaDistributionSetTag("Tag4")); distributionSetManagement.assignTag(Arrays.asList(ds.getId(), ds2.getId()), targetTag); } @@ -86,10 +88,12 @@ public class RSQLDistributionSetFieldTest extends AbstractIntegrationTest { @Test @Description("Test filter distribution set by version") public void testFilterByParameterVersion() { - assertRSQLQuery(DistributionSetFields.VERSION.name() + "==v1.0", 2); - assertRSQLQuery(DistributionSetFields.VERSION.name() + "!=v1.0", 2); - assertRSQLQuery(DistributionSetFields.VERSION.name() + "=in=(v1.0,v1.1)", 3); - assertRSQLQuery(DistributionSetFields.VERSION.name() + "=out=(v1.0,error)", 2); + assertRSQLQuery(DistributionSetFields.VERSION.name() + "==" + TestdataFactory.DEFAULT_VERSION, 1); + assertRSQLQuery(DistributionSetFields.VERSION.name() + "!=" + TestdataFactory.DEFAULT_VERSION, 3); + assertRSQLQuery( + DistributionSetFields.VERSION.name() + "=in=(" + TestdataFactory.DEFAULT_VERSION + ",1.0.0,1.0.1)", 3); + assertRSQLQuery(DistributionSetFields.VERSION.name() + "=out=(" + TestdataFactory.DEFAULT_VERSION + ",error)", + 3); } @Test @@ -118,10 +122,10 @@ public class RSQLDistributionSetFieldTest extends AbstractIntegrationTest { @Test @Description("Test filter distribution set by type") public void testFilterByType() { - assertRSQLQuery(DistributionSetFields.TYPE.name() + "==ecl_os_app_jvm", 4); + assertRSQLQuery(DistributionSetFields.TYPE.name() + "==" + TestdataFactory.DS_TYPE_DEFAULT, 4); assertRSQLQuery(DistributionSetFields.TYPE.name() + "==noExist*", 0); - assertRSQLQuery(DistributionSetFields.TYPE.name() + "=in=(ecl_os_app_jvm,ecl)", 4); - assertRSQLQuery(DistributionSetFields.TYPE.name() + "=out=(ecl_os_app_jvm)", 0); + assertRSQLQuery(DistributionSetFields.TYPE.name() + "=in=(" + TestdataFactory.DS_TYPE_DEFAULT + ",ecl)", 4); + assertRSQLQuery(DistributionSetFields.TYPE.name() + "=out=(" + TestdataFactory.DS_TYPE_DEFAULT + ")", 0); } @Test @@ -137,8 +141,8 @@ public class RSQLDistributionSetFieldTest extends AbstractIntegrationTest { } private void assertRSQLQuery(final String rsqlParam, final long excpectedEntity) { - final Page find = distributionSetManagement.findDistributionSetsAll( - RSQLUtility.parse(rsqlParam, DistributionSetFields.class), new PageRequest(0, 100), false); + final Page find = distributionSetManagement.findDistributionSetsAll(rsqlParam, + new PageRequest(0, 100), false); final long countAll = find.getTotalElements(); assertThat(find).as("Founded entity is should not be null").isNotNull(); assertThat(countAll).as("Founded entity size is wrong").isEqualTo(excpectedEntity); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetMetadataFieldsTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLDistributionSetMetadataFieldsTest.java similarity index 83% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetMetadataFieldsTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLDistributionSetMetadataFieldsTest.java index 755e5a61f..65b677693 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetMetadataFieldsTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLDistributionSetMetadataFieldsTest.java @@ -6,16 +6,16 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import static org.fest.assertions.api.Assertions.assertThat; import java.util.ArrayList; import java.util.List; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.repository.DistributionSetMetadataFields; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.junit.Before; @@ -29,19 +29,18 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("RSQL filter distribution set metadata") -public class RSQLDistributionSetMetadataFieldsTest extends AbstractIntegrationTest { +public class RSQLDistributionSetMetadataFieldsTest extends AbstractJpaIntegrationTest { private Long distributionSetId; @Before public void setupBeforeTest() { - final DistributionSet distributionSet = TestDataUtil.generateDistributionSet("DS", softwareManagement, - distributionSetManagement); + final DistributionSet distributionSet = testdataFactory.createDistributionSet("DS"); distributionSetId = distributionSet.getId(); final List metadata = new ArrayList<>(); for (int i = 0; i < 5; i++) { - metadata.add(new DistributionSetMetadata("" + i, distributionSet, "" + i)); + metadata.add(new JpaDistributionSetMetadata("" + i, distributionSet, "" + i)); } distributionSetManagement.createDistributionSetMetadata(metadata); @@ -68,8 +67,7 @@ public class RSQLDistributionSetMetadataFieldsTest extends AbstractIntegrationTe private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) { final Page findEnitity = distributionSetManagement - .findDistributionSetMetadataByDistributionSetId(distributionSetId, - RSQLUtility.parse(rsqlParam, DistributionSetMetadataFields.class), new PageRequest(0, 100)); + .findDistributionSetMetadataByDistributionSetId(distributionSetId, rsqlParam, new PageRequest(0, 100)); final long countAllEntities = findEnitity.getTotalElements(); assertThat(findEnitity).isNotNull(); assertThat(countAllEntities).isEqualTo(expectedEntities); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLRolloutGroupFields.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLRolloutGroupFields.java similarity index 84% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLRolloutGroupFields.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLRolloutGroupFields.java index 78d333826..fd48aed94 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLRolloutGroupFields.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLRolloutGroupFields.java @@ -6,18 +6,18 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import static org.fest.assertions.api.Assertions.assertThat; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.repository.RolloutGroupFields; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupConditionBuilder; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; import org.junit.Before; import org.junit.Test; import org.springframework.data.domain.Page; @@ -29,7 +29,7 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("RSQL filter rollout group") -public class RSQLRolloutGroupFields extends AbstractIntegrationTest { +public class RSQLRolloutGroupFields extends AbstractJpaIntegrationTest { private Long rolloutGroupId; private Rollout rollout; @@ -37,9 +37,8 @@ public class RSQLRolloutGroupFields extends AbstractIntegrationTest { @Before public void seuptBeforeTest() { final int amountTargets = 20; - targetManagement.createTargets(TestDataUtil.buildTargetFixtures(amountTargets, "rollout", "rollout")); - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); + targetManagement.createTargets(testdataFactory.generateTargets(amountTargets, "rollout", "rollout")); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); rollout = rolloutManagement.findRolloutById(rollout.getId()); this.rolloutGroupId = rollout.getRolloutGroups().get(0).getId(); @@ -75,8 +74,8 @@ public class RSQLRolloutGroupFields extends AbstractIntegrationTest { } private void assertRSQLQuery(final String rsqlParam, final long expcetedTargets) { - final Page findTargetPage = rolloutGroupManagement.findRolloutGroupsByPredicate(rollout, - RSQLUtility.parse(rsqlParam, RolloutGroupFields.class), new PageRequest(0, 100)); + final Page findTargetPage = rolloutGroupManagement.findRolloutGroupsAll(rollout, rsqlParam, + new PageRequest(0, 100)); final long countTargetsAll = findTargetPage.getTotalElements(); assertThat(findTargetPage).isNotNull(); assertThat(countTargetsAll).isEqualTo(expcetedTargets); @@ -84,7 +83,7 @@ public class RSQLRolloutGroupFields extends AbstractIntegrationTest { private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId, final String targetFilterQuery) { - final Rollout rollout = new Rollout(); + final Rollout rollout = new JpaRollout(); rollout.setDistributionSet(distributionSetManagement.findDistributionSetById(distributionSetId)); rollout.setName(name); rollout.setTargetFilterQuery(targetFilterQuery); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleFieldTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleFieldTest.java similarity index 75% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleFieldTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleFieldTest.java index 0c113fd2b..25897ccde 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleFieldTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleFieldTest.java @@ -6,14 +6,17 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import static org.fest.assertions.api.Assertions.assertThat; -import org.eclipse.hawkbit.AbstractIntegrationTest; import org.eclipse.hawkbit.repository.SoftwareModuleFields; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.junit.Before; import org.junit.Test; import org.springframework.data.domain.Page; @@ -25,22 +28,22 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("RSQL filter software module") -public class RSQLSoftwareModuleFieldTest extends AbstractIntegrationTest { +public class RSQLSoftwareModuleFieldTest extends AbstractJpaIntegrationTest { @Before public void setupBeforeTest() { - final SoftwareModule ah = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", "agent-hub", "")); - softwareManagement.createSoftwareModule(new SoftwareModule(runtimeType, "oracle-jre", "1.7.2", "aa", "")); - softwareManagement.createSoftwareModule(new SoftwareModule(osType, "poky", "3.0.2", "aa", "")); + final JpaSoftwareModule ah = (JpaSoftwareModule) softwareManagement + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", "agent-hub", "")); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(runtimeType, "oracle-jre", "1.7.2", "aa", "")); + softwareManagement.createSoftwareModule(new JpaSoftwareModule(osType, "poky", "3.0.2", "aa", "")); - final SoftwareModule ah2 = softwareManagement - .createSoftwareModule(new SoftwareModule(appType, "agent-hub2", "1.0.1", "agent-hub2", "")); + final JpaSoftwareModule ah2 = (JpaSoftwareModule) softwareManagement + .createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub2", "1.0.1", "agent-hub2", "")); - final SoftwareModuleMetadata softwareModuleMetadata = new SoftwareModuleMetadata("metaKey", ah, "metaValue"); + final SoftwareModuleMetadata softwareModuleMetadata = new JpaSoftwareModuleMetadata("metaKey", ah, "metaValue"); softwareManagement.createSoftwareModuleMetadata(softwareModuleMetadata); - final SoftwareModuleMetadata softwareModuleMetadata2 = new SoftwareModuleMetadata("metaKey", ah2, "value"); + final SoftwareModuleMetadata softwareModuleMetadata2 = new JpaSoftwareModuleMetadata("metaKey", ah2, "value"); softwareManagement.createSoftwareModuleMetadata(softwareModuleMetadata2); } @@ -82,10 +85,10 @@ public class RSQLSoftwareModuleFieldTest extends AbstractIntegrationTest { @Test @Description("Test filter software module by type") public void testFilterByType() { - assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "==application", 2); + assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "==" + TestdataFactory.SM_TYPE_APP, 2); assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "==noExist*", 0); - assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "=in=(application)", 2); - assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "=out=(application)", 2); + assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "=in=(" + TestdataFactory.SM_TYPE_APP + ")", 2); + assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "=out=(" + TestdataFactory.SM_TYPE_APP + ")", 2); } @Test @@ -101,8 +104,8 @@ public class RSQLSoftwareModuleFieldTest extends AbstractIntegrationTest { } private void assertRSQLQuery(final String rsqlParam, final long excpectedEntity) { - final Page find = softwareManagement.findSoftwareModulesByPredicate( - RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class), new PageRequest(0, 100)); + final Page find = softwareManagement.findSoftwareModulesByPredicate(rsqlParam, + new PageRequest(0, 100)); final long countAll = find.getTotalElements(); assertThat(find).isNotNull(); assertThat(countAll).isEqualTo(excpectedEntity); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleMetadataFieldsTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleMetadataFieldsTest.java similarity index 80% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleMetadataFieldsTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleMetadataFieldsTest.java index 44fa3e3cd..e04ee8c9b 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleMetadataFieldsTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleMetadataFieldsTest.java @@ -6,18 +6,19 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import static org.fest.assertions.api.Assertions.assertThat; import java.util.ArrayList; import java.util.List; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.junit.Before; import org.junit.Test; import org.springframework.data.domain.Page; @@ -29,20 +30,19 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("RSQL filter software module metadata") -public class RSQLSoftwareModuleMetadataFieldsTest extends AbstractIntegrationTest { +public class RSQLSoftwareModuleMetadataFieldsTest extends AbstractJpaIntegrationTest { private Long softwareModuleId; @Before public void setupBeforeTest() { - final SoftwareModule softwareModule = softwareManagement.createSoftwareModule( - new SoftwareModule(TestDataUtil.findOrCreateSoftwareModuleType(softwareManagement, "application"), - "application", "1.0.0", "Desc", "vendor Limited, California")); + final SoftwareModule softwareModule = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_APP); + softwareModuleId = softwareModule.getId(); final List metadata = new ArrayList<>(); for (int i = 0; i < 5; i++) { - metadata.add(new SoftwareModuleMetadata("" + i, softwareModule, "" + i)); + metadata.add(new JpaSoftwareModuleMetadata("" + i, softwareModule, "" + i)); } softwareManagement.createSoftwareModuleMetadata(metadata); @@ -70,8 +70,7 @@ public class RSQLSoftwareModuleMetadataFieldsTest extends AbstractIntegrationTes private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) { final Page findEnitity = softwareManagement - .findSoftwareModuleMetadataBySoftwareModuleId(softwareModuleId, - RSQLUtility.parse(rsqlParam, SoftwareModuleMetadataFields.class), new PageRequest(0, 100)); + .findSoftwareModuleMetadataBySoftwareModuleId(softwareModuleId, rsqlParam, new PageRequest(0, 100)); final long countAllEntities = findEnitity.getTotalElements(); assertThat(findEnitity).isNotNull(); assertThat(countAllEntities).isEqualTo(expectedEntities); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleTypeFieldsTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleTypeFieldsTest.java similarity index 86% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleTypeFieldsTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleTypeFieldsTest.java index 268bddf50..344d0e320 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleTypeFieldsTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleTypeFieldsTest.java @@ -6,12 +6,13 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import static org.fest.assertions.api.Assertions.assertThat; -import org.eclipse.hawkbit.AbstractIntegrationTest; +import org.eclipse.hawkbit.repository.Constants; import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.junit.Test; import org.springframework.data.domain.Page; @@ -23,7 +24,7 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("RSQL filter software module test type") -public class RSQLSoftwareModuleTypeFieldsTest extends AbstractIntegrationTest { +public class RSQLSoftwareModuleTypeFieldsTest extends AbstractJpaIntegrationTest { @Test @Description("Test filter software module test type by id") @@ -34,7 +35,7 @@ public class RSQLSoftwareModuleTypeFieldsTest extends AbstractIntegrationTest { @Test @Description("Test filter software module test type by name") public void testFilterByParameterName() { - assertRSQLQuery(SoftwareModuleTypeFields.NAME.name() + "==ECL*", 3); + assertRSQLQuery(SoftwareModuleTypeFields.NAME.name() + "==" + Constants.SMT_DEFAULT_OS_NAME, 1); } @Test @@ -55,12 +56,12 @@ public class RSQLSoftwareModuleTypeFieldsTest extends AbstractIntegrationTest { @Test @Description("Test filter software module test type by max") public void testFilterByMaxAssignment() { - assertRSQLQuery(SoftwareModuleTypeFields.MAXASSIGNMENTS.name() + "==1", 3); + assertRSQLQuery(SoftwareModuleTypeFields.MAXASSIGNMENTS.name() + "==1", 2); } private void assertRSQLQuery(final String rsqlParam, final long excpectedEntity) { - final Page find = softwareManagement.findSoftwareModuleTypesByPredicate( - RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class), new PageRequest(0, 100)); + final Page find = softwareManagement.findSoftwareModuleTypesAll(rsqlParam, + new PageRequest(0, 100)); final long countAll = find.getTotalElements(); assertThat(find).isNotNull(); assertThat(countAll).isEqualTo(excpectedEntity); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTagFieldsTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTagFieldsTest.java similarity index 87% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTagFieldsTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTagFieldsTest.java index b35ed13d1..3772bb372 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTagFieldsTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTagFieldsTest.java @@ -6,12 +6,14 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import static org.fest.assertions.api.Assertions.assertThat; -import org.eclipse.hawkbit.AbstractIntegrationTest; import org.eclipse.hawkbit.repository.TagFields; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.TargetTag; import org.junit.Before; @@ -25,15 +27,15 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("RSQL filter target and distribution set tags") -public class RSQLTagFieldsTest extends AbstractIntegrationTest { +public class RSQLTagFieldsTest extends AbstractJpaIntegrationTest { @Before public void seuptBeforeTest() { for (int i = 0; i < 5; i++) { - final TargetTag targetTag = new TargetTag("" + i, "" + i, i % 2 == 0 ? "red" : "blue"); + final TargetTag targetTag = new JpaTargetTag("" + i, "" + i, i % 2 == 0 ? "red" : "blue"); tagManagement.createTargetTag(targetTag); - final DistributionSetTag distributionSetTag = new DistributionSetTag("" + i, "" + i, + final DistributionSetTag distributionSetTag = new JpaDistributionSetTag("" + i, "" + i, i % 2 == 0 ? "red" : "blue"); tagManagement.createDistributionSetTag(distributionSetTag); } @@ -101,8 +103,8 @@ public class RSQLTagFieldsTest extends AbstractIntegrationTest { private void assertRSQLQueryDistributionSet(final String rsqlParam, final long expectedEntities) { - final Page findEnitity = tagManagement - .findAllDistributionSetTags(RSQLUtility.parse(rsqlParam, TagFields.class), new PageRequest(0, 100)); + final Page findEnitity = tagManagement.findAllDistributionSetTags(rsqlParam, + new PageRequest(0, 100)); final long countAllEntities = findEnitity.getTotalElements(); assertThat(findEnitity).isNotNull(); assertThat(countAllEntities).isEqualTo(expectedEntities); @@ -110,8 +112,7 @@ public class RSQLTagFieldsTest extends AbstractIntegrationTest { private void assertRSQLQueryTarget(final String rsqlParam, final long expectedEntities) { - final Page findEnitity = tagManagement - .findAllTargetTags(RSQLUtility.parse(rsqlParam, TagFields.class), new PageRequest(0, 100)); + final Page findEnitity = tagManagement.findAllTargetTags(rsqlParam, new PageRequest(0, 100)); final long countAllEntities = findEnitity.getTotalElements(); assertThat(findEnitity).isNotNull(); assertThat(countAllEntities).isEqualTo(expectedEntities); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTargetFieldTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFieldTest.java similarity index 70% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTargetFieldTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFieldTest.java index 54efab860..cdac51614 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTargetFieldTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFieldTest.java @@ -6,21 +6,25 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.fail; import java.util.Arrays; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.repository.TargetFields; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; +import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.junit.Before; import org.junit.Test; import org.springframework.data.domain.Page; @@ -32,35 +36,37 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("RSQL filter target") -public class RSQLTargetFieldTest extends AbstractIntegrationTest { +public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest { + private static final long LAST_TARGET_QUERY = 10000; + private static final long LAST_TARGET_QUERY_SMALLER = 1000; @Before public void seuptBeforeTest() { - final DistributionSet ds = TestDataUtil.generateDistributionSet("AssignedDs", softwareManagement, - distributionSetManagement); + final DistributionSet ds = testdataFactory.createDistributionSet("AssignedDs"); - final Target target = new Target("targetId123"); + final Target target = entityFactory.generateTarget("targetId123"); target.setDescription("targetId123"); - final TargetInfo targetInfo = new TargetInfo(target); + final TargetInfo targetInfo = target.getTargetInfo(); targetInfo.getControllerAttributes().put("revision", "1.1"); - target.setTargetInfo(targetInfo); - target.getTargetInfo().setUpdateStatus(TargetUpdateStatus.PENDING); - + ((JpaTargetInfo) target.getTargetInfo()).setUpdateStatus(TargetUpdateStatus.PENDING); + ((JpaTargetInfo) target.getTargetInfo()).setLastTargetQuery(LAST_TARGET_QUERY); targetManagement.createTarget(target); - final Target target2 = new Target("targetId1234"); - target2.setDescription("targetId1234"); - final TargetInfo targetInfo2 = new TargetInfo(target2); - targetInfo2.getControllerAttributes().put("revision", "1.2"); - target2.setTargetInfo(targetInfo2); - targetManagement.createTarget(target2); - targetManagement.createTarget(new Target("targetId1235")); - targetManagement.createTarget(new Target("targetId1236")); - final TargetTag targetTag = tagManagement.createTargetTag(new TargetTag("Tag1")); - tagManagement.createTargetTag(new TargetTag("Tag2")); - tagManagement.createTargetTag(new TargetTag("Tag3")); - tagManagement.createTargetTag(new TargetTag("Tag4")); + final JpaTarget target2 = new JpaTarget("targetId1234"); + target2.setDescription("targetId1234"); + final TargetInfo targetInfo2 = target2.getTargetInfo(); + targetInfo2.getControllerAttributes().put("revision", "1.2"); + ((JpaTargetInfo) target2.getTargetInfo()).setLastTargetQuery(LAST_TARGET_QUERY_SMALLER); + targetManagement.createTarget(target2); + + targetManagement.createTarget(new JpaTarget("targetId1235")); + targetManagement.createTarget(new JpaTarget("targetId1236")); + + final TargetTag targetTag = tagManagement.createTargetTag(new JpaTargetTag("Tag1")); + tagManagement.createTargetTag(new JpaTargetTag("Tag2")); + tagManagement.createTargetTag(new JpaTargetTag("Tag3")); + tagManagement.createTargetTag(new JpaTargetTag("Tag4")); targetManagement.assignTag(Arrays.asList(target.getControllerId(), target2.getControllerId()), targetTag); @@ -145,11 +151,13 @@ public class RSQLTargetFieldTest extends AbstractIntegrationTest { @Test @Description("Test filter target by assigned ds version") public void testFilterByAssignedDsVersion() { - assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==v1.0", 1); + assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==" + TestdataFactory.DEFAULT_VERSION, 1); assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==*1*", 1); assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==noExist*", 0); - assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version=in=(v1.0,notexist)", 1); - assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version=out=(v1.0,notexist)", 0); + assertRSQLQuery( + TargetFields.ASSIGNEDDS.name() + ".version=in=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 1); + assertRSQLQuery( + TargetFields.ASSIGNEDDS.name() + ".version=out=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 0); } @Test @@ -162,9 +170,19 @@ public class RSQLTargetFieldTest extends AbstractIntegrationTest { assertRSQLQuery(TargetFields.TAG.name() + "=out=(Tag1,notexist)", 0); } + @Test + @Description("Test filter target by lastTargetQuery") + public void testFilterByLastTargetQuery() { + assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "==" + LAST_TARGET_QUERY, 1); + assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "!=" + LAST_TARGET_QUERY, 1); + assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=lt=" + LAST_TARGET_QUERY, 1); + assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=lt=" + LAST_TARGET_QUERY_SMALLER, 0); + assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=gt=" + LAST_TARGET_QUERY_SMALLER, 1); + assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=gt=" + LAST_TARGET_QUERY, 0); + } + private void assertRSQLQuery(final String rsqlParam, final long expcetedTargets) { - final Page findTargetPage = targetManagement - .findTargetsAll(RSQLUtility.parse(rsqlParam, TargetFields.class), new PageRequest(0, 100)); + final Page findTargetPage = targetManagement.findTargetsAll(rsqlParam, new PageRequest(0, 100)); final long countTargetsAll = findTargetPage.getTotalElements(); assertThat(findTargetPage).isNotNull(); assertThat(countTargetsAll).isEqualTo(expcetedTargets); diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLUtilityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java similarity index 98% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLUtilityTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java index 356464bc2..04901d948 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLUtilityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.rsql; +package org.eclipse.hawkbit.repository.jpa.rsql; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; @@ -30,6 +30,8 @@ import org.eclipse.hawkbit.repository.DistributionSetFields; import org.eclipse.hawkbit.repository.FieldNameProvider; import org.eclipse.hawkbit.repository.SoftwareModuleFields; import org.eclipse.hawkbit.repository.TargetFields; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/tenancy/MultiTenancyEntityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/tenancy/MultiTenancyEntityTest.java similarity index 91% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/tenancy/MultiTenancyEntityTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/tenancy/MultiTenancyEntityTest.java index 67b9b5a26..52f314171 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/tenancy/MultiTenancyEntityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/tenancy/MultiTenancyEntityTest.java @@ -6,16 +6,18 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.tenancy; +package org.eclipse.hawkbit.repository.jpa.tenancy; import static org.fest.assertions.api.Assertions.assertThat; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.WithSpringAuthorityRule; -import org.eclipse.hawkbit.WithUser; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.Test; import org.springframework.data.domain.Page; import org.springframework.data.domain.Slice; @@ -32,7 +34,7 @@ import ru.yandex.qatools.allure.annotations.Stories; */ @Features("Component Tests - Repository") @Stories("Multi Tenancy") -public class MultiTenancyEntityTest extends AbstractIntegrationTest { +public class MultiTenancyEntityTest extends AbstractJpaIntegrationTest { @Test @Description(value = "Ensures that multiple targets with same controller-ID can be created for different tenants.") @@ -162,7 +164,7 @@ public class MultiTenancyEntityTest extends AbstractIntegrationTest { private Target createTargetForTenant(final String controllerId, final String tenant) throws Exception { return securityRule.runAs(WithSpringAuthorityRule.withUserAndTenant("user", tenant), - () -> targetManagement.createTarget(new Target(controllerId))); + () -> targetManagement.createTarget(new JpaTarget(controllerId))); } private Slice findTargetsForTenant(final String tenant) throws Exception { @@ -180,19 +182,19 @@ public class MultiTenancyEntityTest extends AbstractIntegrationTest { private DistributionSet createDistributionSetForTenant(final String name, final String version, final String tenant) throws Exception { return securityRule.runAs(WithSpringAuthorityRule.withUserAndTenant("user", tenant), () -> { - final DistributionSet ds = new DistributionSet(); + final JpaDistributionSet ds = new JpaDistributionSet(); ds.setName(name); ds.setTenant(tenant); ds.setVersion(version); ds.setType(distributionSetManagement - .createDistributionSetType(new DistributionSetType("typetest", "test", "foobar"))); + .createDistributionSetType(new JpaDistributionSetType("typetest", "test", "foobar"))); return distributionSetManagement.createDistributionSet(ds); }); } private Page findDistributionSetForTenant(final String tenant) throws Exception { return securityRule.runAs(WithSpringAuthorityRule.withUserAndTenant("user", tenant), - () -> distributionSetManagement.findDistributionSetsAll(pageReq, false, false)); + () -> distributionSetManagement.findDistributionSetsByDeletedAndOrCompleted(pageReq, false, false)); } } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/utils/MultipleInvokeHelper.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/utils/MultipleInvokeHelper.java similarity index 98% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/utils/MultipleInvokeHelper.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/utils/MultipleInvokeHelper.java index d40fe1fd0..c4710ca4b 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/utils/MultipleInvokeHelper.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/utils/MultipleInvokeHelper.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.utils; +package org.eclipse.hawkbit.repository.jpa.utils; import java.util.concurrent.Callable; diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/utils/SuccessCondition.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/utils/SuccessCondition.java similarity index 92% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/utils/SuccessCondition.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/utils/SuccessCondition.java index 6c9553dc8..b5e421107 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/utils/SuccessCondition.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/utils/SuccessCondition.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.utils; +package org.eclipse.hawkbit.repository.jpa.utils; /** * SuccessCondition Interface. diff --git a/hawkbit-repository/src/test/resources/application-test.properties b/hawkbit-repository/hawkbit-repository-jpa/src/test/resources/application-test.properties similarity index 100% rename from hawkbit-repository/src/test/resources/application-test.properties rename to hawkbit-repository/hawkbit-repository-jpa/src/test/resources/application-test.properties diff --git a/hawkbit-repository/hawkbit-repository-test/pom.xml b/hawkbit-repository/hawkbit-repository-test/pom.xml new file mode 100644 index 000000000..4a05735ac --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-test/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + org.eclipse.hawkbit + hawkbit-repository + 0.2.0-SNAPSHOT + + hawkbit-repository-test + hawkBit :: Repository Test Utilities + + + + org.eclipse.hawkbit + hawkbit-repository-api + ${project.version} + + + org.eclipse.hawkbit + hawkbit-repository-core + ${project.version} + + + org.eclipse.hawkbit + hawkbit-artifact-repository-mongo + ${project.version} + + + org.springframework + spring-context-support + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + + + net._01001111 + jlorem + + + commons-io + commons-io + 2.5 + + + org.springframework.boot + spring-boot-starter-test + + + org.springframework.security + spring-security-config + + + org.springframework.security + spring-security-aspects + + + org.springframework + spring-test + + + org.springframework.security + spring-security-web + + + \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/matcher/BaseEntityMatcher.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/matcher/BaseEntityMatcher.java new file mode 100644 index 000000000..cb3f5476f --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/matcher/BaseEntityMatcher.java @@ -0,0 +1,42 @@ +/** + * 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.test.matcher; + +import org.eclipse.hawkbit.repository.model.BaseEntity; +import org.hamcrest.Factory; +import org.hamcrest.FeatureMatcher; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +/** + * Matcher for {@link BaseEntity}. + */ +public class BaseEntityMatcher { + + private BaseEntityMatcher() { + } + + @Factory + public static Matcher hasId(final Long id) { + return new HasIdMatcher(Matchers.equalTo(id)); + } + + private static class HasIdMatcher extends FeatureMatcher { + + public HasIdMatcher(final Matcher subMatcher) { + super(subMatcher, "getId()", "id"); + } + + @Override + protected Long featureValueOf(final BaseEntity baseEntity) { + return baseEntity.getId(); + } + } + +} diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/AbstractIntegrationTest.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java similarity index 55% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/AbstractIntegrationTest.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java index ddd850df1..3d09fabc3 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/AbstractIntegrationTest.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java @@ -6,47 +6,25 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.test.util; -import static org.fest.assertions.api.Assertions.assertThat; - -import java.util.List; - -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; - -import org.eclipse.hawkbit.cache.TenantAwareCacheManager; -import org.eclipse.hawkbit.repository.ActionRepository; -import org.eclipse.hawkbit.repository.ActionStatusRepository; +import org.eclipse.hawkbit.ExcludePathAwareShallowETagFilter; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement; -import org.eclipse.hawkbit.repository.DistributionSetRepository; -import org.eclipse.hawkbit.repository.DistributionSetTagRepository; -import org.eclipse.hawkbit.repository.DistributionSetTypeRepository; -import org.eclipse.hawkbit.repository.ExternalArtifactRepository; -import org.eclipse.hawkbit.repository.LocalArtifactRepository; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.RolloutGroupManagement; -import org.eclipse.hawkbit.repository.RolloutGroupRepository; import org.eclipse.hawkbit.repository.RolloutManagement; -import org.eclipse.hawkbit.repository.RolloutRepository; import org.eclipse.hawkbit.repository.SoftwareManagement; -import org.eclipse.hawkbit.repository.SoftwareModuleMetadataRepository; -import org.eclipse.hawkbit.repository.SoftwareModuleRepository; -import org.eclipse.hawkbit.repository.SoftwareModuleTypeRepository; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.TagManagement; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; -import org.eclipse.hawkbit.repository.TargetInfoRepository; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.TargetRepository; -import org.eclipse.hawkbit.repository.TargetTagRepository; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.repository.TenantMetaDataRepository; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.utils.RepositoryDataGenerator.DatabaseCleanupUtil; import org.eclipse.hawkbit.security.DosFilter; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; @@ -67,22 +45,21 @@ import org.springframework.core.env.Environment; import org.springframework.data.auditing.AuditingHandler; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import org.springframework.data.mongodb.gridfs.GridFsOperations; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration -@SpringApplicationConfiguration(classes = { RepositoryApplicationConfiguration.class, TestConfiguration.class }) @ActiveProfiles({ "test" }) @WithUser(principal = "bumlux", allSpPermissions = true, authorities = "ROLE_CONTROLLER") +@SpringApplicationConfiguration(classes = { TestConfiguration.class }) // destroy the context after each test class because otherwise we get problem // when context is // refreshed we e.g. get two instances of CacheManager which leads to very @@ -93,44 +70,16 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware { protected static final Pageable pageReq = new PageRequest(0, 400); - @PersistenceContext - protected EntityManager entityManager; + /** + * Number of {@link DistributionSetType}s that exist in every test case. One + * generated by using + * {@link TestdataFactory#findOrCreateDefaultTestDsType()} and two + * {@link SystemManagement#getTenantMetadata()}; + */ + protected static final int DEFAULT_DS_TYPES = RepositoryConstants.DEFAULT_DS_TYPES_IN_TENANT + 1; @Autowired - protected TargetRepository targetRepository; - - @Autowired - protected ActionRepository actionRepository; - - @Autowired - protected DistributionSetRepository distributionSetRepository; - - @Autowired - protected SoftwareModuleRepository softwareModuleRepository; - - @Autowired - protected TenantMetaDataRepository tenantMetaDataRepository; - - @Autowired - protected DistributionSetTypeRepository distributionSetTypeRepository; - - @Autowired - protected SoftwareModuleTypeRepository softwareModuleTypeRepository; - - @Autowired - protected TargetTagRepository targetTagRepository; - - @Autowired - protected DistributionSetTagRepository distributionSetTagRepository; - - @Autowired - protected SoftwareModuleMetadataRepository softwareModuleMetadataRepository; - - @Autowired - protected ActionStatusRepository actionStatusRepository; - - @Autowired - protected ExternalArtifactRepository externalArtifactRepository; + protected EntityFactory entityFactory; @Autowired protected SoftwareManagement softwareManagement; @@ -156,15 +105,6 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware { @Autowired protected ArtifactManagement artifactManagement; - @Autowired - protected LocalArtifactRepository artifactRepository; - - @Autowired - protected TargetInfoRepository targetInfoRepository; - - @Autowired - protected GridFsOperations operations; - @Autowired protected WebApplicationContext context; @@ -180,9 +120,6 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware { @Autowired protected SystemManagement systemManagement; - @Autowired - protected TenantAwareCacheManager cacheManager; - @Autowired protected TenantConfigurationManagement tenantConfigurationManagement; @@ -192,19 +129,13 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware { @Autowired protected RolloutGroupManagement rolloutGroupManagement; - @Autowired - protected RolloutGroupRepository rolloutGroupRepository; - - @Autowired - protected RolloutRepository rolloutRepository; - @Autowired protected SystemSecurityContext systemSecurityContext; - protected MockMvc mvc; - @Autowired - protected DatabaseCleanupUtil dbCleanupUtil; + protected TestRepositoryManagement testRepositoryManagement; + + protected MockMvc mvc; protected SoftwareModuleType osType; protected SoftwareModuleType appType; @@ -212,13 +143,14 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware { protected DistributionSetType standardDsType; + @Autowired + protected TestdataFactory testdataFactory; + @Rule public final WithSpringAuthorityRule securityRule = new WithSpringAuthorityRule(); protected Environment environment = null; - private static CIMySqlTestDatabase tesdatabase; - @Override public void setEnvironment(final Environment environment) { this.environment = environment; @@ -226,79 +158,38 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware { @Before public void before() throws Exception { - mvc = MockMvcBuilders.webAppContextSetup(context) - .addFilter(new DosFilter(100, 10, "127\\.0\\.0\\.1|\\[0:0:0:0:0:0:0:1\\]", "(^192\\.168\\.)", - "X-Forwarded-For")) - .addFilter(new ExcludePathAwareShallowETagFilter( - "/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download", "/*/controller/artifacts/**")) - .build(); + mvc = createMvcWebAppContext().build(); + final String description = "Updated description to have lastmodified available in tests"; - standardDsType = securityRule.runAsPrivileged(() -> systemManagement.getTenantMetadata().getDefaultDsType()); - - osType = securityRule.runAsPrivileged(() -> softwareManagement.findSoftwareModuleTypeByKey("os")); - osType.setDescription("Updated description to have lastmodified available in tests"); + osType = securityRule + .runAsPrivileged(() -> testdataFactory.findOrCreateSoftwareModuleType(TestdataFactory.SM_TYPE_OS)); + osType.setDescription(description); osType = securityRule.runAsPrivileged(() -> softwareManagement.updateSoftwareModuleType(osType)); - appType = securityRule.runAsPrivileged(() -> softwareManagement.findSoftwareModuleTypeByKey("application")); - appType.setDescription("Updated description to have lastmodified available in tests"); + appType = securityRule.runAsPrivileged( + () -> testdataFactory.findOrCreateSoftwareModuleType(TestdataFactory.SM_TYPE_APP, Integer.MAX_VALUE)); + appType.setDescription(description); appType = securityRule.runAsPrivileged(() -> softwareManagement.updateSoftwareModuleType(appType)); - runtimeType = securityRule.runAsPrivileged(() -> softwareManagement.findSoftwareModuleTypeByKey("runtime")); - runtimeType.setDescription("Updated description to have lastmodified available in tests"); + runtimeType = securityRule + .runAsPrivileged(() -> testdataFactory.findOrCreateSoftwareModuleType(TestdataFactory.SM_TYPE_RT)); + runtimeType.setDescription(description); runtimeType = securityRule.runAsPrivileged(() -> softwareManagement.updateSoftwareModuleType(runtimeType)); - } - @BeforeClass - public static void beforeClass() { - createTestdatabaseAndStart(); - } - - private static void createTestdatabaseAndStart() { - if ("MYSQL".equals(System.getProperty("spring.jpa.database"))) { - tesdatabase = new CIMySqlTestDatabase(); - tesdatabase.before(); - } - } - - @AfterClass - public static void afterClass() { - if (tesdatabase != null) { - tesdatabase.after(); - } + standardDsType = securityRule.runAsPrivileged(() -> testdataFactory.findOrCreateDefaultTestDsType()); } @After - public void after() throws Exception { - deleteAllRepos(); - cacheManager.getDirectCacheNames().forEach(name -> cacheManager.getDirectCache(name).clear()); - assertThat(actionStatusRepository.findAll()).isEmpty(); - assertThat(targetRepository.findAll()).isEmpty(); - assertThat(actionRepository.findAll()).isEmpty(); - assertThat(distributionSetRepository.findAll()).isEmpty(); - assertThat(targetTagRepository.findAll()).isEmpty(); - assertThat(distributionSetTagRepository.findAll()).isEmpty(); - assertThat(softwareModuleRepository.findAll()).isEmpty(); - assertThat(softwareModuleTypeRepository.findAll()).isEmpty(); - assertThat(distributionSetTypeRepository.findAll()).isEmpty(); - assertThat(tenantMetaDataRepository.findAll()).isEmpty(); - assertThat(rolloutGroupRepository.findAll()).isEmpty(); - assertThat(rolloutRepository.findAll()).isEmpty(); + public void after() { + testRepositoryManagement.clearTestRepository(); } - @Transactional - protected void deleteAllRepos() throws Exception { - final List tenants = securityRule.runAs(WithSpringAuthorityRule.withUser(false), - () -> systemManagement.findTenants()); - tenants.forEach(tenant -> { - try { - securityRule.runAs(WithSpringAuthorityRule.withUser(false), () -> { - systemManagement.deleteTenant(tenant); - return null; - }); - } catch (final Exception e) { - e.printStackTrace(); - } - }); + protected DefaultMockMvcBuilder createMvcWebAppContext() { + return MockMvcBuilders.webAppContextSetup(context) + .addFilter(new DosFilter(100, 10, "127\\.0\\.0\\.1|\\[0:0:0:0:0:0:0:1\\]", "(^192\\.168\\.)", + "X-Forwarded-For")) + .addFilter(new ExcludePathAwareShallowETagFilter( + "/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download", "/*/controller/artifacts/**")); } @Rule @@ -324,4 +215,25 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware { } } }; + + private static CIMySqlTestDatabase tesdatabase; + + @BeforeClass + public static void beforeClass() { + createTestdatabaseAndStart(); + } + + private static void createTestdatabaseAndStart() { + if ("MYSQL".equals(System.getProperty("spring.jpa.database"))) { + tesdatabase = new CIMySqlTestDatabase(); + tesdatabase.before(); + } + } + + @AfterClass + public static void afterClass() { + if (tesdatabase != null) { + tesdatabase.after(); + } + } } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/AbstractIntegrationTestWithMongoDB.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTestWithMongoDB.java similarity index 89% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/AbstractIntegrationTestWithMongoDB.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTestWithMongoDB.java index 6d116c5f0..bb54f550c 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/AbstractIntegrationTestWithMongoDB.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTestWithMongoDB.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.test.util; import java.io.IOException; import java.net.UnknownHostException; @@ -15,7 +15,9 @@ import java.util.concurrent.atomic.AtomicInteger; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.gridfs.GridFsOperations; import de.flapdoodle.embed.mongo.Command; import de.flapdoodle.embed.mongo.MongodExecutable; @@ -38,10 +40,14 @@ import de.flapdoodle.embed.process.runtime.Network; * */ public abstract class AbstractIntegrationTestWithMongoDB extends AbstractIntegrationTest { + protected static volatile MongodExecutable mongodExecutable = null; private static final AtomicInteger mongoLease = new AtomicInteger(0); private static volatile Integer port; + @Autowired + protected GridFsOperations operations; + @BeforeClass public static void setupMongo() throws UnknownHostException, IOException { mongoLease.incrementAndGet(); @@ -67,8 +73,8 @@ public abstract class AbstractIntegrationTestWithMongoDB extends AbstractIntegra new ArtifactStoreBuilder().defaults(command) .download(new DownloadConfigBuilder().defaultsForCommand(command) .proxyFactory(new HttpProxyFactory( - System.getProperty("http.proxyHost").trim(), - Integer.valueOf(System.getProperty("http.proxyPort")))))); + System.getProperty("http.proxyHost").trim(), Integer + .valueOf(System.getProperty("http.proxyPort")))))); } final IMongodConfig mongodConfig = new MongodConfigBuilder().version(version) @@ -86,7 +92,7 @@ public abstract class AbstractIntegrationTestWithMongoDB extends AbstractIntegra operations.delete(new Query()); } - public void internalShutDownMongo() { + public static void internalShutDownMongo() { if (mongodExecutable != null && mongoLease.decrementAndGet() <= 0) { mongodExecutable.stop(); mongodExecutable = null; diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/CIMySqlTestDatabase.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/CIMySqlTestDatabase.java similarity index 70% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/CIMySqlTestDatabase.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/CIMySqlTestDatabase.java index 0a9b4b1b3..3601f896e 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/CIMySqlTestDatabase.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/CIMySqlTestDatabase.java @@ -6,10 +6,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.test.util; import java.sql.Connection; import java.sql.DriverManager; +import java.sql.PreparedStatement; import java.sql.SQLException; import org.apache.commons.lang3.RandomStringUtils; @@ -17,17 +18,20 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * + * {@link Testdatabase} implementation for MySQL. * */ public class CIMySqlTestDatabase implements Testdatabase { - private final static Logger LOG = LoggerFactory.getLogger(CIMySqlTestDatabase.class); + private static final Logger LOG = LoggerFactory.getLogger(CIMySqlTestDatabase.class); private String schemaName; private String uri; private final String username; private final String password; + /** + * Constructor. + */ public CIMySqlTestDatabase() { this.username = System.getProperty("spring.datasource.username"); this.password = System.getProperty("spring.datasource.password"); @@ -43,7 +47,7 @@ public class CIMySqlTestDatabase implements Testdatabase { private void createSchemaUri() { schemaName = "SP" + RandomStringUtils.randomAlphanumeric(10); - this.uri = this.uri.substring(0, uri.lastIndexOf("/") + 1); + this.uri = this.uri.substring(0, uri.lastIndexOf('/') + 1); System.setProperty("spring.datasource.url", uri + schemaName); } @@ -55,10 +59,12 @@ public class CIMySqlTestDatabase implements Testdatabase { private void createSchema() { try (Connection connection = DriverManager.getConnection(uri, username, password)) { - connection.prepareStatement("CREATE SCHEMA " + schemaName + ";").execute(); - LOG.info("Schema {} created on uri {}", schemaName, uri); + try (PreparedStatement statement = connection.prepareStatement("CREATE SCHEMA " + schemaName + ";")) { + statement.execute(); + LOG.info("Schema {} created on uri {}", schemaName, uri); + } } catch (final SQLException e) { - e.printStackTrace(); + LOG.error("Schema creation failed!", e); } } @@ -70,10 +76,12 @@ public class CIMySqlTestDatabase implements Testdatabase { private void dropSchema() { try (Connection connection = DriverManager.getConnection(uri, username, password)) { - connection.prepareStatement("DROP SCHEMA " + schemaName + ";").execute(); - LOG.info("Schema {} dropped on uri {}", schemaName, uri); + try (PreparedStatement statement = connection.prepareStatement("DROP SCHEMA " + schemaName + ";")) { + statement.execute(); + LOG.info("Schema {} dropped on uri {}", schemaName, uri); + } } catch (final SQLException e) { - e.printStackTrace(); + LOG.error("Schema drop failed!", e); } } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/FreePortFileWriter.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/FreePortFileWriter.java similarity index 97% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/FreePortFileWriter.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/FreePortFileWriter.java index c67928910..149cdf2b5 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/FreePortFileWriter.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/FreePortFileWriter.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.test.util; import java.io.File; import java.net.InetSocketAddress; diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/HashGeneratorUtils.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/HashGeneratorUtils.java similarity index 74% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/HashGeneratorUtils.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/HashGeneratorUtils.java index 10f4ede4c..9d1dbca7c 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/HashGeneratorUtils.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/HashGeneratorUtils.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.test.util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -14,13 +14,10 @@ import java.security.NoSuchAlgorithmException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.io.BaseEncoding; + /** - * Hash utility calls copied from - * http://www.codejava.net/coding/how-to-calculate-md5-and-sha-hash-values-in- - * java. - * - * - * + * Hash digest utility. */ public final class HashGeneratorUtils { @@ -68,18 +65,11 @@ public final class HashGeneratorUtils { try { final MessageDigest digest = MessageDigest.getInstance(algorithm); final byte[] hashedBytes = digest.digest(message); - return convertByteArrayToHexString(hashedBytes); + return BaseEncoding.base16().lowerCase().encode(hashedBytes); } catch (final NoSuchAlgorithmException e) { - LOG.error("Algorithm could not be find", e); + LOG.error("Algorithm could not be found", e); } return null; } - private static String convertByteArrayToHexString(final byte[] arrayBytes) { - final StringBuilder builder = new StringBuilder(); - for (int i = 0; i < arrayBytes.length; i++) { - builder.append(Integer.toString((arrayBytes[i] & 0xff) + 0x100, 16).substring(1)); - } - return builder.toString(); - } } diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/JpaTestRepositoryManagement.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/JpaTestRepositoryManagement.java new file mode 100644 index 000000000..eae0b9a7d --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/JpaTestRepositoryManagement.java @@ -0,0 +1,50 @@ +/** + * 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.test.util; + +import java.util.List; + +import org.eclipse.hawkbit.cache.TenantAwareCacheManager; +import org.eclipse.hawkbit.repository.SystemManagement; +import org.eclipse.hawkbit.security.SystemSecurityContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +public class JpaTestRepositoryManagement implements TestRepositoryManagement { + + @Autowired + private TenantAwareCacheManager cacheManager; + + @Autowired + private SystemSecurityContext systemSecurityContext; + + @Autowired + private SystemManagement systemManagement; + + @Override + public void clearTestRepository() { + deleteAllRepos(); + cacheManager.getDirectCacheNames().forEach(name -> cacheManager.getDirectCache(name).clear()); + } + + @Transactional + public void deleteAllRepos() { + final List tenants = systemSecurityContext.runAsSystem(() -> systemManagement.findTenants()); + tenants.forEach(tenant -> { + try { + systemSecurityContext.runAsSystem(() -> { + systemManagement.deleteTenant(tenant); + return null; + }); + } catch (final Exception e) { + e.printStackTrace(); + } + }); + } +} diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestConfiguration.java similarity index 85% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestConfiguration.java index d96856557..3a7a2f73d 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestConfiguration.java @@ -6,17 +6,16 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.test.util; import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import org.eclipse.hawkbit.HawkbitServerProperties; import org.eclipse.hawkbit.cache.CacheConstants; import org.eclipse.hawkbit.cache.TenancyCacheManager; import org.eclipse.hawkbit.cache.TenantAwareCacheManager; -import org.eclipse.hawkbit.repository.model.helper.EventBusHolder; -import org.eclipse.hawkbit.repository.utils.RepositoryDataGenerator; -import org.eclipse.hawkbit.repository.utils.RepositoryDataGenerator.DatabaseCleanupUtil; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.SecurityContextTenantAware; import org.eclipse.hawkbit.security.SpringSecurityAuditorAware; @@ -32,7 +31,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.data.domain.AuditorAware; import org.springframework.scheduling.annotation.AsyncConfigurer; -import org.springframework.security.concurrent.DelegatingSecurityContextExecutor; +import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import com.google.common.eventbus.AsyncEventBus; @@ -51,14 +50,14 @@ import com.mongodb.MongoClientOptions; @Profile("test") public class TestConfiguration implements AsyncConfigurer { - /** - * DB cleanup utility bean is created. - * - * @return the {@link DatabaseCleanupUtil} bean - */ @Bean - public DatabaseCleanupUtil createDatabaseCleanupUtil() { - return new RepositoryDataGenerator.DatabaseCleanupUtil(); + public TestRepositoryManagement testRepositoryManagement() { + return new JpaTestRepositoryManagement(); + } + + @Bean + public TestdataFactory testdataFactory() { + return new TestdataFactory(); } @Bean @@ -100,7 +99,7 @@ public class TestConfiguration implements AsyncConfigurer { @Bean public Executor asyncExecutor() { - return new DelegatingSecurityContextExecutor(Executors.newSingleThreadExecutor()); + return new DelegatingSecurityContextExecutorService(Executors.newSingleThreadExecutor()); } @Bean diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestRepositoryManagement.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestRepositoryManagement.java new file mode 100644 index 000000000..482c7725c --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestRepositoryManagement.java @@ -0,0 +1,22 @@ +/** + * 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.test.util; + +/** + * Repository support for tests. + * + */ +@FunctionalInterface +public interface TestRepositoryManagement { + /** + * Empty the test repository. + */ + void clearTestRepository(); + +} diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java new file mode 100644 index 000000000..81e2c1daf --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java @@ -0,0 +1,743 @@ +/** + * 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.test.util; + +import java.io.InputStream; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; +import java.util.UUID; + +import org.apache.commons.io.IOUtils; +import org.eclipse.hawkbit.repository.ArtifactManagement; +import org.eclipse.hawkbit.repository.ControllerManagement; +import org.eclipse.hawkbit.repository.DeploymentManagement; +import org.eclipse.hawkbit.repository.DistributionSetManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.SoftwareManagement; +import org.eclipse.hawkbit.repository.TagManagement; +import org.eclipse.hawkbit.repository.TargetManagement; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.Artifact; +import org.eclipse.hawkbit.repository.model.BaseEntity; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.NamedEntity; +import org.eclipse.hawkbit.repository.model.NamedVersionedEntity; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetTag; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; + +import net._01001111.text.LoremIpsum; + +/** + * Data generator utility for tests. + */ +public class TestdataFactory { + private static final LoremIpsum LOREM = new LoremIpsum(); + + /** + * default {@link Target#getControllerId()}. + */ + public static final String DEFAULT_CONTROLLER_ID = "targetExist"; + + /** + * Default {@link SoftwareModule#getVendor()}. + */ + public static final String DEFAULT_VENDOR = "Vendor Limited, California"; + + /** + * Default {@link NamedVersionedEntity#getVersion()}. + */ + public static final String DEFAULT_VERSION = "1.0"; + + /** + * Default {@link NamedEntity#getDescription()}. + */ + public static final String DEFAULT_DESCRIPTION = "Desc: " + LOREM.words(10); + + /** + * Key of test default {@link DistributionSetType}. + */ + public static final String DS_TYPE_DEFAULT = "test_default_ds_type"; + + /** + * Key of test "os" {@link SoftwareModuleType} -> mandatory firmware in + * {@link #DS_TYPE_DEFAULT}. + */ + public static final String SM_TYPE_OS = "os"; + + /** + * Key of test "runtime" {@link SoftwareModuleType} -> optional firmware in + * {@link #DS_TYPE_DEFAULT}. + */ + public static final String SM_TYPE_RT = "runtime"; + + /** + * Key of test "application" {@link SoftwareModuleType} -> optional software + * in {@link #DS_TYPE_DEFAULT}. + */ + public static final String SM_TYPE_APP = "application"; + + @Autowired + private ControllerManagement controllerManagament; + + @Autowired + private SoftwareManagement softwareManagement; + + @Autowired + private DistributionSetManagement distributionSetManagement; + + @Autowired + private TargetManagement targetManagement; + + @Autowired + private DeploymentManagement deploymentManagement; + + @Autowired + private TagManagement tagManagement; + + @Autowired + private EntityFactory entityFactory; + + @Autowired + private ArtifactManagement artifactManagement; + + /** + * Creates {@link DistributionSet} in repository including three + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} + * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and + * {@link DistributionSet#isRequiredMigrationStep()} false. + * + * @param prefix + * for {@link SoftwareModule}s and {@link DistributionSet}s name, + * vendor and description. + * + * @return {@link DistributionSet} entity. + */ + public DistributionSet createDistributionSet(final String prefix) { + return createDistributionSet(prefix, DEFAULT_VERSION, false); + } + + /** + * Creates {@link DistributionSet} in repository including three + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} + * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION}. + * + * @param prefix + * for {@link SoftwareModule}s and {@link DistributionSet}s name, + * vendor and description. + * @param isRequiredMigrationStep + * for {@link DistributionSet#isRequiredMigrationStep()} + * + * @return {@link DistributionSet} entity. + */ + public DistributionSet createDistributionSet(final String prefix, final boolean isRequiredMigrationStep) { + return createDistributionSet(prefix, DEFAULT_VERSION, isRequiredMigrationStep); + } + + /** + * Creates {@link DistributionSet} in repository including three + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} + * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and + * {@link DistributionSet#isRequiredMigrationStep()} false. + * + * @param prefix + * for {@link SoftwareModule}s and {@link DistributionSet}s name, + * vendor and description. + * @param tags + * {@link DistributionSet#getTags()} + * + * @return {@link DistributionSet} entity. + */ + public DistributionSet createDistributionSet(final String prefix, final Collection tags) { + return createDistributionSet(prefix, DEFAULT_VERSION, tags); + } + + /** + * Creates {@link DistributionSet} in repository including three + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} + * , {@link #SM_TYPE_APP}. + * + * @param prefix + * for {@link SoftwareModule}s and {@link DistributionSet}s name, + * vendor and description. + * @param version + * {@link DistributionSet#getVersion()} and + * {@link SoftwareModule#getVersion()} extended by a random + * number. + * @param isRequiredMigrationStep + * for {@link DistributionSet#isRequiredMigrationStep()} + * + * @return {@link DistributionSet} entity. + */ + public DistributionSet createDistributionSet(final String prefix, final String version, + final boolean isRequiredMigrationStep) { + + final SoftwareModule appMod = softwareManagement.createSoftwareModule(entityFactory.generateSoftwareModule( + findOrCreateSoftwareModuleType(SM_TYPE_APP, Integer.MAX_VALUE), prefix + SM_TYPE_APP, + version + "." + new Random().nextInt(100), LOREM.words(20), prefix + " vendor Limited, California")); + final SoftwareModule runtimeMod = softwareManagement + .createSoftwareModule(entityFactory.generateSoftwareModule(findOrCreateSoftwareModuleType(SM_TYPE_RT), + prefix + "app runtime", version + "." + new Random().nextInt(100), LOREM.words(20), + prefix + " vendor GmbH, Stuttgart, Germany")); + final SoftwareModule osMod = softwareManagement + .createSoftwareModule(entityFactory.generateSoftwareModule(findOrCreateSoftwareModuleType(SM_TYPE_OS), + prefix + " Firmware", version + "." + new Random().nextInt(100), LOREM.words(20), + prefix + " vendor Limited Inc, California")); + + return distributionSetManagement + .createDistributionSet(generateDistributionSet(prefix != null && prefix.length() > 0 ? prefix : "DS", + version, findOrCreateDefaultTestDsType(), Lists.newArrayList(osMod, runtimeMod, appMod)) + .setRequiredMigrationStep(isRequiredMigrationStep)); + } + + /** + * Creates {@link DistributionSet} in repository including three + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} + * , {@link #SM_TYPE_APP}. + * + * @param prefix + * for {@link SoftwareModule}s and {@link DistributionSet}s name, + * vendor and description. + * @param version + * {@link DistributionSet#getVersion()} and + * {@link SoftwareModule#getVersion()} extended by a random + * number.updat + * @param tags + * {@link DistributionSet#getTags()} + * + * @return {@link DistributionSet} entity. + */ + public DistributionSet createDistributionSet(final String prefix, final String version, + final Collection tags) { + + final DistributionSet set = createDistributionSet(prefix, version, false); + + final List sets = new ArrayList<>(); + sets.add(set); + + tags.forEach(tag -> distributionSetManagement.toggleTagAssignment(sets, tag)); + + return distributionSetManagement.findDistributionSetById(set.getId()); + + } + + /** + * Creates {@link DistributionSet}s in repository including three + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} + * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} followed by an + * iterative number and {@link DistributionSet#isRequiredMigrationStep()} + * false. + * + * @param number + * of {@link DistributionSet}s to create + * + * @return {@link List} of {@link DistributionSet} entities + */ + public List createDistributionSets(final int number) { + + return createDistributionSets("", number); + } + + /** + * Creates {@link DistributionSet}s in repository including three + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} + * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} followed by an + * iterative number and {@link DistributionSet#isRequiredMigrationStep()} + * false. + * + * @param prefix + * for {@link SoftwareModule}s and {@link DistributionSet}s name, + * vendor and description. + * @param number + * of {@link DistributionSet}s to create + * + * @return {@link List} of {@link DistributionSet} entities + */ + public List createDistributionSets(final String prefix, final int number) { + + final List sets = new ArrayList<>(); + for (int i = 0; i < number; i++) { + sets.add(createDistributionSet(prefix, DEFAULT_VERSION + "." + i, false)); + } + + return sets; + } + + /** + * Creates {@link DistributionSet}s in repository with + * {@link #DEFAULT_DESCRIPTION} and + * {@link DistributionSet#isRequiredMigrationStep()} false. + * + * @param name + * {@link DistributionSet#getName()} + * @param version + * {@link DistributionSet#getVersion()} + * + * @return {@link DistributionSet} entity + */ + public DistributionSet createDistributionSetWithNoSoftwareModules(final String name, final String version) { + + final DistributionSet dis = entityFactory.generateDistributionSet(); + dis.setName(name); + dis.setVersion(version); + dis.setDescription(DEFAULT_DESCRIPTION); + dis.setType(findOrCreateDefaultTestDsType()); + return distributionSetManagement.createDistributionSet(dis); + } + + /** + * Creates {@link LocalArtifact}s for given {@link SoftwareModule} with a + * small text payload. + * + * @param moduleId + * the {@link Artifact}s belong to. + * + * @return {@link LocalArtifact} entity. + */ + public List createLocalArtifacts(final Long moduleId) { + final List artifacts = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + final InputStream stubInputStream = IOUtils.toInputStream("some test data" + i, Charset.forName("UTF-8")); + artifacts.add(artifactManagement.createLocalArtifact(stubInputStream, moduleId, "filename" + i, false)); + + } + + return artifacts; + } + + /** + * Creates {@link SoftwareModule} with {@link #DEFAULT_VENDOR} and + * {@link #DEFAULT_VERSION} and random generated + * {@link Target#getDescription()} in the repository. + * + * @param typeKey + * of the {@link SoftwareModuleType} + * + * @return persisted {@link SoftwareModule}. + */ + public SoftwareModule createSoftwareModule(final String typeKey) { + return softwareManagement.createSoftwareModule(entityFactory.generateSoftwareModule( + findOrCreateSoftwareModuleType(typeKey), typeKey, DEFAULT_VERSION, LOREM.words(10), DEFAULT_VENDOR)); + } + + /** + * @return persisted {@link Target} with {@link #DEFAULT_CONTROLLER_ID}. + */ + public Target createTarget() { + return targetManagement.createTarget(entityFactory.generateTarget(DEFAULT_CONTROLLER_ID)); + } + + /** + * Creates {@link DistributionSet}s in repository including three + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} + * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} followed by an + * iterative number and {@link DistributionSet#isRequiredMigrationStep()} + * false. + * + * In addition it updates the ccreated {@link DistributionSet}s and + * {@link SoftwareModule}s to ensure that + * {@link BaseEntity#getLastModifiedAt()} and + * {@link BaseEntity#getLastModifiedBy()} is filled. + * + * @return persisted {@link DistributionSet}. + */ + public DistributionSet createUpdatedDistributionSet() { + DistributionSet set = createDistributionSet(""); + set.setVersion(DEFAULT_VERSION); + set = distributionSetManagement.updateDistributionSet(set); + + set.getModules().forEach(module -> { + module.setDescription("Updated " + DEFAULT_DESCRIPTION); + softwareManagement.updateSoftwareModule(module); + }); + + // load also lazy stuff + set = distributionSetManagement.findDistributionSetByIdWithDetails(set.getId()); + + return set; + } + + /** + * @return {@link DistributionSetType} with key {@link #DS_TYPE_DEFAULT} and + * {@link SoftwareModuleType}s {@link #SM_TYPE_OS}, + * {@link #SM_TYPE_RT} , {@link #SM_TYPE_APP}. + */ + public DistributionSetType findOrCreateDefaultTestDsType() { + final List mand = new ArrayList<>(); + mand.add(findOrCreateSoftwareModuleType(SM_TYPE_OS)); + + final List opt = new ArrayList<>(); + opt.add(findOrCreateSoftwareModuleType(SM_TYPE_APP, Integer.MAX_VALUE)); + opt.add(findOrCreateSoftwareModuleType(SM_TYPE_RT)); + + return findOrCreateDistributionSetType(DS_TYPE_DEFAULT, "OS (FW) mandatory, runtime (FW) and app (SW) optional", + mand, opt); + } + + /** + * Creates {@link DistributionSetType} in repository. + * + * @param dsTypeKey + * {@link DistributionSetType#getKey()} + * @param dsTypeName + * {@link DistributionSetType#getName()} + * + * @return persisted {@link DistributionSetType} + */ + public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKey, final String dsTypeName) { + final DistributionSetType findDistributionSetTypeByname = distributionSetManagement + .findDistributionSetTypeByKey(dsTypeKey); + + if (findDistributionSetTypeByname != null) { + return findDistributionSetTypeByname; + } + + final DistributionSetType type = entityFactory.generateDistributionSetType(dsTypeKey, dsTypeName, + LOREM.words(10)); + + return distributionSetManagement.createDistributionSetType(type); + } + + /** + * Finds {@link DistributionSetType} in repository with given + * {@link DistributionSetType#getKey()} or creates if it does not exist yet. + * + * @param dsTypeKey + * {@link DistributionSetType#getKey()} + * @param dsTypeName + * {@link DistributionSetType#getName()} + * @param mandatory + * {@link DistributionSetType#getMandatoryModuleTypes()} + * @param optional + * {@link DistributionSetType#getOptionalModuleTypes()} + * + * @return persisted {@link DistributionSetType} + */ + public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKey, final String dsTypeName, + final Collection mandatory, final Collection optional) { + final DistributionSetType findDistributionSetTypeByname = distributionSetManagement + .findDistributionSetTypeByKey(dsTypeKey); + + if (findDistributionSetTypeByname != null) { + return findDistributionSetTypeByname; + } + + final DistributionSetType type = entityFactory.generateDistributionSetType(dsTypeKey, dsTypeName, + LOREM.words(10)); + mandatory.forEach(type::addMandatoryModuleType); + optional.forEach(type::addOptionalModuleType); + + return distributionSetManagement.createDistributionSetType(type); + } + + /** + * Finds {@link SoftwareModuleType} in repository with given + * {@link SoftwareModuleType#getKey()} or creates if it does not exist yet + * with {@link SoftwareModuleType#getMaxAssignments()} = 1. + * + * @param key + * {@link SoftwareModuleType#getKey()} + * + * @return persisted {@link SoftwareModuleType} + */ + public SoftwareModuleType findOrCreateSoftwareModuleType(final String key) { + return findOrCreateSoftwareModuleType(key, 1); + } + + /** + * Finds {@link SoftwareModuleType} in repository with given + * {@link SoftwareModuleType#getKey()} or creates if it does not exist yet. + * + * @param key + * {@link SoftwareModuleType#getKey()} + * @param maxAssignments + * {@link SoftwareModuleType#getMaxAssignments()} + * + * @return persisted {@link SoftwareModuleType} + */ + public SoftwareModuleType findOrCreateSoftwareModuleType(final String key, final int maxAssignments) { + final SoftwareModuleType findSoftwareModuleTypeByKey = softwareManagement.findSoftwareModuleTypeByKey(key); + if (findSoftwareModuleTypeByKey != null) { + return findSoftwareModuleTypeByKey; + } + return softwareManagement.createSoftwareModuleType( + entityFactory.generateSoftwareModuleType(key, key, LOREM.words(10), maxAssignments)); + } + + /** + * builder method for creating a {@link DistributionSet}. + * + * @param name + * {@link DistributionSet#getName()} + * @param version + * {@link DistributionSet#getVersion()} + * @param type + * {@link DistributionSet#getType()} + * @param modules + * {@link DistributionSet#getModules()} + * + * @return the created {@link DistributionSet} + */ + public DistributionSet generateDistributionSet(final String name, final String version, + final DistributionSetType type, final Collection modules) { + final DistributionSet distributionSet = entityFactory.generateDistributionSet(name, version, null, type, + modules); + distributionSet.setDescription(LOREM.words(10)); + return distributionSet; + } + + /** + * Creates {@link DistributionSetTag}s in repository. + * + * @param number + * of {@link DistributionSetTag}s + * + * @return the persisted {@link DistributionSetTag}s + */ + public List createDistributionSetTags(final int number) { + final List result = new ArrayList<>(); + + for (int i = 0; i < number; i++) { + result.add(entityFactory.generateDistributionSetTag("tag" + i, "tagdesc" + i, String.valueOf(i))); + } + + return tagManagement.createDistributionSetTags(result); + } + + /** + * builder method for creating a single target object. + * + * @param ctrlID + * the ID of the target + * @param description + * of the target + * @return the created target object + */ + public Target generateTarget(final String ctrlID, final String description) { + return generateTarget(ctrlID, description, null); + } + + /** + * Builds a single {@link Target} from the given parameters. + * + * @param ctrlID + * controllerID + * @param description + * the description of the target + * @param tags + * assigned {@link TargetTag}s + * @return the generated {@link Target} + */ + private Target generateTarget(final String ctrlID, final String description, final TargetTag[] tags) { + final Target target = entityFactory.generateTarget(ctrlID); + target.setName("Prov.Target ".concat(ctrlID)); + target.setDescription(description); + if (tags != null && tags.length > 0) { + for (final TargetTag t : tags) { + target.getTags().add(t); + } + } + return target; + } + + /** + * Creates {@link Target}s in repository and with + * {@link #DEFAULT_CONTROLLER_ID} as prefix for + * {@link Target#getControllerId()}. + * + * @param number + * of {@link Target}s to create + * + * @return {@link List} of {@link Target} entities + */ + public List createTargets(final int number) { + return targetManagement.createTargets(generateTargets(0, number, DEFAULT_CONTROLLER_ID)); + } + + /** + * Builds {@link Target} objects with given prefix for + * {@link Target#getControllerId()} followed by a number suffix. + * + * @param start + * value for the controllerId suffix + * @param numberOfTargets + * of {@link Target}s to generate + * @param controllerIdPrefix + * for {@link Target#getControllerId()} generation. + * @return list of {@link Target} objects + */ + private List generateTargets(final int start, final int numberOfTargets, final String controllerIdPrefix) { + final List targets = new ArrayList<>(); + for (int i = start; i < start + numberOfTargets; i++) { + targets.add(entityFactory.generateTarget(controllerIdPrefix + i)); + } + + return targets; + } + + /** + * Builds {@link Target} objects with given prefix for + * {@link Target#getControllerId()} followed by a number suffix starting + * with 0. + * + * @param numberOfTargets + * of {@link Target}s to generate + * @param controllerIdPrefix + * for {@link Target#getControllerId()} generation. + * @return list of {@link Target} objects + */ + public List generateTargets(final int numberOfTargets, final String controllerIdPrefix) { + return generateTargets(0, numberOfTargets, controllerIdPrefix); + } + + /** + * builds a set of {@link Target} fixtures from the given parameters. + * + * @param numberOfTargets + * number of targets to create + * @param controllerIdPrefix + * prefix used for the controller ID + * @param descriptionPrefix + * prefix used for the description + * @return set of {@link Target} + */ + public List generateTargets(final int numberOfTargets, final String controllerIdPrefix, + final String descriptionPrefix) { + return generateTargets(numberOfTargets, controllerIdPrefix, descriptionPrefix, null); + } + + /** + * method creates set of targets by by generating the controller ID and the + * description like: prefix + no of target. + * + * @param noOfTgts + * number of targets which should be created + * @param controllerIdPrefix + * prefix of the controllerID which is concatenated with the + * number of the target. Randomly generated if null. + * @param descriptionPrefix + * prefix of the target description which is concatenated with + * the number of the target + * @param tags + * tags which should be added to the created {@link Target}s + * @return set of created targets + */ + private List generateTargets(final int noOfTgts, final String controllerIdPrefix, + final String descriptionPrefix, final TargetTag[] tags) { + final List list = new ArrayList<>(); + for (int i = 0; i < noOfTgts; i++) { + String ctrlID = controllerIdPrefix; + if (Strings.isNullOrEmpty(ctrlID)) { + ctrlID = UUID.randomUUID().toString(); + } + ctrlID = String.format("%s-%05d", ctrlID, i); + + final String description = descriptionPrefix + DEFAULT_DESCRIPTION; + + final Target target = generateTarget(ctrlID, description, tags); + list.add(target); + + } + return list; + } + + /** + * Generates {@link TargetTag}s. + * + * @param number + * of {@link TargetTag}s to generate. + * + * @return generated {@link TargetTag}s. + */ + public List generateTargetTags(final int number) { + final List result = new ArrayList<>(); + + for (int i = 0; i < number; i++) { + result.add(entityFactory.generateTargetTag("tag" + i, "tagdesc" + i, String.valueOf(i))); + } + + return result; + } + + /** + * Create a set of {@link TargetTag}s. + * + * @param noOfTags + * number of {@link TargetTag}. to be created + * @param tagPrefix + * prefix for the {@link TargetTag#getName()} + * @return the created set of {@link TargetTag}s + */ + public List generateTargetTags(final int noOfTags, final String tagPrefix) { + final List list = new ArrayList<>(); + for (int i = 0; i < noOfTags; i++) { + String tagName = "myTag"; + if (!Strings.isNullOrEmpty(tagPrefix)) { + tagName = tagPrefix; + } + tagName = String.format("%s-%05d", tagName, i); + + final TargetTag targetTag = entityFactory.generateTargetTag(tagName); + list.add(targetTag); + } + return list; + } + + private Action sendUpdateActionStatusToTarget(final Status status, final Action updActA, final String... msgs) { + updActA.setStatus(status); + + final ActionStatus statusMessages = entityFactory.generateActionStatus(); + statusMessages.setAction(updActA); + statusMessages.setOccurredAt(System.currentTimeMillis()); + statusMessages.setStatus(status); + for (final String msg : msgs) { + statusMessages.addMessage(msg); + } + + return controllerManagament.addUpdateActionStatus(statusMessages); + } + + /** + * Append {@link ActionStatus} to all {@link Action}s of given + * {@link Target}s. + * + * @param targets + * to add {@link ActionStatus} + * @param status + * to add + * @param msgs + * to add + * + * @return updated {@link Action}. + */ + public List sendUpdateActionStatusToTargets(final Collection targets, final Status status, + final String... msgs) { + final List result = new ArrayList<>(); + for (final Target target : targets) { + final List findByTarget = deploymentManagement.findActionsByTarget(target); + for (final Action action : findByTarget) { + result.add(sendUpdateActionStatusToTarget(status, action, msgs)); + } + } + return result; + } +} diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/Testdatabase.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/Testdatabase.java similarity index 90% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/Testdatabase.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/Testdatabase.java index a11984481..e6f9be49f 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/Testdatabase.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/Testdatabase.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.test.util; /** * diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/WithSpringAuthorityRule.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithSpringAuthorityRule.java similarity index 97% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/WithSpringAuthorityRule.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithSpringAuthorityRule.java index 40f6a64c2..a2bc90555 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/WithSpringAuthorityRule.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithSpringAuthorityRule.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.test.util; import java.lang.annotation.Annotation; import java.lang.reflect.Field; @@ -17,7 +17,7 @@ import java.util.concurrent.Callable; import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; -import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.SystemManagementHolder; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; @@ -63,7 +63,7 @@ public class WithSpringAuthorityRule implements TestRule { } return oldContext; } - + /** * @param annotation */ @@ -129,6 +129,14 @@ public class WithSpringAuthorityRule implements TestRule { private void after(final SecurityContext oldContext) { SecurityContextHolder.setContext(oldContext); } + + /** + * Clears the current security context. + */ + public void clear() + { + SecurityContextHolder.clearContext(); + } /** * @param callable diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/WithUser.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithUser.java similarity index 97% rename from hawkbit-repository/src/test/java/org/eclipse/hawkbit/WithUser.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithUser.java index 3b0412ff1..a6151ed4c 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/WithUser.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithUser.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.repository.test.util; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; diff --git a/hawkbit-repository/pom.xml b/hawkbit-repository/pom.xml index b70e00f28..981f3225a 100644 --- a/hawkbit-repository/pom.xml +++ b/hawkbit-repository/pom.xml @@ -18,245 +18,14 @@ hawkbit-repository hawkBit :: Repository + pom + + + hawkbit-repository-jpa + hawkbit-repository-api + hawkbit-repository-test + hawkbit-repository-core + - - - - com.ethlo.eclipselink.tools - http://ethlo.com/maven - - - - - - com.ethlo.eclipselink.tools - http://ethlo.com/maven - - - - - - - - com.fasterxml.jackson.core - jackson-core - - - com.fasterxml.jackson.core - jackson-databind - - - - - org.eclipse.hawkbit - hawkbit-artifact-repository-mongo - ${project.version} - - - org.eclipse.hawkbit - hawkbit-core - ${project.version} - - - org.eclipse.hawkbit - hawkbit-security-core - ${project.version} - - - org.hibernate - hibernate-validator - - - javax.validation - validation-api - - - com.google.guava - guava - - - net._01001111 - jlorem - - - org.springframework.boot - spring-boot - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.eclipse.persistence - org.eclipse.persistence.jpa - - - org.springframework.security - spring-security-core - - - org.springframework.hateoas - spring-hateoas - - - org.flywaydb - flyway-core - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - - com.h2database - h2 - test - - - org.mariadb.jdbc - mariadb-java-client - test - - - javax.el - javax.el-api - test - - - org.springframework - spring-context-support - test - - - org.eclipse.hawkbit - hawkbit-rest-api - ${project.version} - test - - - ru.yandex.qatools.allure - allure-junit-adaptor - test - - - org.springframework.data - spring-data-rest-webmvc - test - - - org.springframework.security - spring-security-aspects - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework - spring-test - test - - - org.easytesting - fest-assert-core - test - - - org.easytesting - fest-assert - test - - - de.flapdoodle.embed - de.flapdoodle.embed.mongo - test - - - org.springframework.security - spring-security-config - test - - - org.springframework.security - spring-security-web - test - - - cz.jirutka.rsql - rsql-parser - - - - - - - - org.bsc.maven - maven-processor-plugin - - - process - - process - - generate-sources - - - org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor - - - - - - - org.hibernate - hibernate-jpamodelgen - ${hibernate.version} - - - - - - com.ethlo.persistence.tools - eclipselink-maven-plugin - 2.6.2 - - - process-classes - - weave - - - - - - org.eclipse.persistence - org.eclipse.persistence.jpa - ${eclipselink.version} - - - org.javassist - javassist - 3.20.0-GA - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java deleted file mode 100644 index d5e8db96f..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java +++ /dev/null @@ -1,175 +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; - -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.hawkbit.aspects.ExceptionMappingAspectHandler; -import org.eclipse.hawkbit.repository.SystemManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.repository.model.helper.AfterTransactionCommitExecutorHolder; -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; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.EnableAspectJAutoProxy; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; -import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.annotation.EnableTransactionManagement; -import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; - -/** - * General configuration for the SP Repository. - * - */ -@EnableJpaRepositories(basePackages = { "org.eclipse.hawkbit.repository" }) -@EnableTransactionManagement -@EnableJpaAuditing -@EnableAspectJAutoProxy -@Configuration -@ComponentScan -@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 TenantConfigurationManagementHolder tenantConfigurationManagementHolder() { - return TenantConfigurationManagementHolder.getInstance(); - } - - /** - * @return the {@link SystemManagementHolder} singleton bean which holds the - * current {@link SystemManagement} service and make it accessible - * in beans which cannot access the service directly, e.g. JPA - * entities. - */ - @Bean - public SystemManagementHolder systemManagementHolder() { - return SystemManagementHolder.getInstance(); - } - - /** - * @return the {@link TenantAwareHolder} singleton bean which holds the - * current {@link TenantAware} service and make it accessible in - * beans which cannot access the service directly, e.g. JPA - * entities. - */ - @Bean - public TenantAwareHolder tenantAwareHolder() { - return TenantAwareHolder.getInstance(); - } - - /** - * @return the {@link SecurityTokenGeneratorHolder} singleton bean which - * holds the current {@link SecurityTokenGenerator} service and make - * it accessible in beans which cannot access the service via - * injection - */ - @Bean - public SecurityTokenGeneratorHolder securityTokenGeneratorHolder() { - return SecurityTokenGeneratorHolder.getInstance(); - } - - /** - * @return the singleton instance of the {@link CacheManagerHolder} - */ - @Bean - public CacheManagerHolder cacheManagerHolder() { - return CacheManagerHolder.getInstance(); - } - - /** - * - * @return the singleton instance of the - * {@link AfterTransactionCommitExecutorHolder} - */ - @Bean - public AfterTransactionCommitExecutorHolder afterTransactionCommitExecutorHolder() { - return AfterTransactionCommitExecutorHolder.getInstance(); - } - - /** - * Defines the validation processor bean. - * - * @return the {@link MethodValidationPostProcessor} - */ - @Bean - public MethodValidationPostProcessor methodValidationPostProcessor() { - return new MethodValidationPostProcessor(); - } - - /** - * @return {@link ExceptionMappingAspectHandler} aspect bean - */ - @Bean - public ExceptionMappingAspectHandler createRepositoryExceptionHandlerAdvice() { - return new ExceptionMappingAspectHandler(); - } - - @Override - protected AbstractJpaVendorAdapter createJpaVendorAdapter() { - return new EclipseLinkJpaVendorAdapter(); - } - - @Override - protected Map getVendorProperties() { - - final Map properties = new HashMap<>(); - // Turn off dynamic weaving to disable LTW lookup in static weaving mode - properties.put("eclipselink.weaving", "false"); - // needed for reports - properties.put("eclipselink.jdbc.allow-native-sql-queries", "true"); - // flyway - properties.put("eclipselink.ddl-generation", "none"); - - properties.put("eclipselink.persistence-context.flush-mode", "auto"); - - return properties; - } - - /** - * {@link MultiTenantJpaTransactionManager} bean. - * - * @see org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration#transactionManager() - * @return a new {@link PlatformTransactionManager} - */ - @Override - @Bean - public PlatformTransactionManager transactionManager() { - return new MultiTenantJpaTransactionManager(); - } -} 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 deleted file mode 100644 index 024ec11cb..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java +++ /dev/null @@ -1,495 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository; - -import java.io.InputStream; -import java.util.List; - -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.artifact.repository.ArtifactRepository; -import org.eclipse.hawkbit.artifact.repository.ArtifactStoreException; -import org.eclipse.hawkbit.artifact.repository.HashNotMatchException; -import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; -import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash; -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.exception.ArtifactDeleteFailedException; -import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.exception.GridFSDBFileNotFoundException; -import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException; -import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException; -import org.eclipse.hawkbit.repository.model.Artifact; -import org.eclipse.hawkbit.repository.model.ExternalArtifact; -import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider; -import org.eclipse.hawkbit.repository.model.LocalArtifact; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.specifications.SoftwareModuleSpecification; -import org.hibernate.validator.constraints.NotEmpty; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.domain.Specification; -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. - * - */ -@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -@Validated -@Service -public class ArtifactManagement { - - private static final Logger LOG = LoggerFactory.getLogger(ArtifactManagement.class); - - @Autowired - private LocalArtifactRepository localArtifactRepository; - - @Autowired - private ExternalArtifactRepository externalArtifactRepository; - - @Autowired - private SoftwareModuleRepository softwareModuleRepository; - - @Autowired - private ExternalArtifactProviderRepository externalArtifactProviderRepository; - - @Autowired - private ArtifactRepository artifactRepository; - - /** - * Persists artifact binary as provided by given InputStream. assign the - * artifact in addition to given {@link SoftwareModule}. - * - * @param stream - * to read from for artifact binary - * @param moduleId - * to assign the new artifact to - * @param filename - * of the artifact - * @param providedSha1Sum - * optional sha1 checksum to check the new file against - * @param providedMd5Sum - * optional md5 checksum to check the new file against - * @param overrideExisting - * to true if the artifact binary can be overdiden - * if it already exists - * @param contentType - * the contentType of the file - * @return uploaded {@link LocalArtifact} - * - * @throws EntityNotFoundException - * if given software module does not exist - * @throws EntityAlreadyExistsException - * if File with that name already exists in the Software Module - * @throws ArtifactUploadFailedException - * if upload fails with internal server errors - * @throws InvalidMD5HashException - * if check against provided MD5 checksum failed - * @throws InvalidSHA1HashException - * if check against provided SHA1 checksum failed - */ - @Modifying - @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, - final boolean overrideExisting, final String contentType) { - DbArtifact result = null; - - final SoftwareModule softwareModule = getModuleAndThrowExceptionIfThatFails(moduleId); - - final LocalArtifact existing = checkForExistingArtifact(filename, overrideExisting, softwareModule); - - try { - result = artifactRepository.store(stream, filename, contentType, - new DbArtifactHash(providedSha1Sum, providedMd5Sum)); - } catch (final ArtifactStoreException e) { - throw new ArtifactUploadFailedException(e); - } catch (final HashNotMatchException e) { - if (e.getHashFunction().equals(HashNotMatchException.SHA1)) { - throw new InvalidSHA1HashException(e.getMessage(), e); - } else { - throw new InvalidMD5HashException(e.getMessage(), e); - } - } - if (result == null) { - return null; - } - - return storeArtifactMetadata(softwareModule, filename, result, existing); - } - - private static LocalArtifact checkForExistingArtifact(final String filename, final boolean overrideExisting, - final SoftwareModule softwareModule) { - if (softwareModule.getLocalArtifactByFilename(filename).isPresent()) { - if (overrideExisting) { - LOG.debug("overriding existing artifact with new filename {}", filename); - return softwareModule.getLocalArtifactByFilename(filename).get(); - } else { - throw new EntityAlreadyExistsException("File with that name already exists in the Software Module"); - } - } - return null; - } - - private SoftwareModule getModuleAndThrowExceptionIfThatFails(final Long moduleId) { - final SoftwareModule softwareModule = findSoftwareModuleWithDetails(moduleId); - - if (softwareModule == null) { - LOG.debug("no software module with ID {} exists", moduleId); - throw new EntityNotFoundException("Software Module: " + moduleId); - } - return softwareModule; - } - - /** - * Retrieves software module including details ( - * {@link SoftwareModule#getArtifacts()}). - * - * @param id - * parameter - * @param isDeleted - * parameter - * @return the found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - protected SoftwareModule findSoftwareModuleWithDetails(@NotNull final Long id) { - final SoftwareModule result = findSoftwareModuleById(id); - if (result != null) { - result.getArtifacts().size(); - } - - return result; - } - - /** - * Find all local artifact by sha1 and return the first artifact. - * - * @param sha1 - * the sha1 - * @return the first local artifact - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) - public LocalArtifact findFirstLocalArtifactsBySHA1(final String sha1) { - return localArtifactRepository.findFirstByGridFsFileName(sha1); - } - - /** - * Finds {@link SoftwareModule} by given id. - * - * @param id - * to search for - * @return the found {@link SoftwareModule}s or null if not - * found. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) - protected SoftwareModule findSoftwareModuleById(@NotNull final Long id) { - - final Specification spec = SoftwareModuleSpecification.byId(id); - - return softwareModuleRepository.findOne(spec); - } - - private LocalArtifact storeArtifactMetadata(final SoftwareModule softwareModule, final String providedFilename, - final DbArtifact result, final LocalArtifact existing) { - LocalArtifact artifact = existing; - if (existing == null) { - artifact = new LocalArtifact(result.getHashes().getSha1(), providedFilename, softwareModule); - } - artifact.setMd5Hash(result.getHashes().getMd5()); - artifact.setSha1Hash(result.getHashes().getSha1()); - artifact.setSize(result.getSize()); - - LOG.debug("storing new artifact into repository {}", artifact); - return localArtifactRepository.save(artifact); - } - - /** - * Persists {@link ExternalArtifactProvider} based on given properties. - * - * @param name - * of the provided - * @param description - * which is optional - * @param basePath - * of all {@link ExternalArtifact}s of the provider - * @param defaultUrlSuffix - * that is used if {@link ExternalArtifact#getUrlSuffix()} is - * empty. - * @return created {@link ExternalArtifactProvider} - */ - @Modifying - @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) { - return externalArtifactProviderRepository - .save(new ExternalArtifactProvider(name, description, basePath, defaultUrlSuffix)); - } - - /** - * Creates {@link ExternalArtifact} based on given provider. - * - * @param externalRepository - * the artifact is located in - * @param urlSuffix - * of the artifact - * {@link ExternalArtifactProvider#getDefaultSuffix()} is used if - * empty. - * @param moduleId - * to assign the artifact to - * - * @return created {@link ExternalArtifact} - * - * @throws EntityNotFoundException - * if {@link SoftwareModule} with given ID does not exist - */ - @Modifying - @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); - return externalArtifactRepository.save(new ExternalArtifact(externalRepository, urlSuffix, module)); - } - - /** - * Deletes {@link Artifact} based on given id. - * - * @param id - * of the {@link Artifact} that has to be deleted. - * @throws ArtifactDeleteFailedException - * if deletion failed (MongoDB is not available) - * - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - public void deleteLocalArtifact(@NotNull final Long id) { - final LocalArtifact existing = localArtifactRepository.findOne(id); - - if (null == existing) { - return; - } - - deleteGridFsArtifact(existing); - - existing.getSoftwareModule().removeArtifact(existing); - softwareModuleRepository.save(existing.getSoftwareModule()); - localArtifactRepository.delete(id); - } - - /** - * Delete a grid fs file. - * - * @param existing - * the related local artifact - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - public void deleteGridFsArtifact(@NotNull final LocalArtifact existing) { - if (existing == null) { - return; - } - - boolean artifactIsOnlyUsedByOneSoftwareModule = true; - for (final LocalArtifact lArtifact : localArtifactRepository - .findByGridFsFileName(existing.getGridFsFileName())) { - if (!lArtifact.getSoftwareModule().isDeleted() - && Long.compare(lArtifact.getSoftwareModule().getId(), existing.getSoftwareModule().getId()) != 0) { - artifactIsOnlyUsedByOneSoftwareModule = false; - break; - } - } - - if (artifactIsOnlyUsedByOneSoftwareModule) { - try { - LOG.debug("deleting artifact from repository {}", existing.getGridFsFileName()); - artifactRepository.deleteBySha1(existing.getGridFsFileName()); - } catch (final ArtifactStoreException e) { - throw new ArtifactDeleteFailedException(e); - } - } - } - - /** - * Deletes {@link Artifact} based on given id. - * - * @param id - * of the {@link Artifact} that has to be deleted. - * @throws ArtifactDeleteFailedException - * if deletion failed (MongoDB is not available) - * - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - public void deleteExternalArtifact(@NotNull final Long id) { - final ExternalArtifact existing = externalArtifactRepository.findOne(id); - - if (null == existing) { - return; - } - - existing.getSoftwareModule().removeArtifact(existing); - softwareModuleRepository.save(existing.getSoftwareModule()); - externalArtifactRepository.delete(id); - } - - /** - * Searches for {@link Artifact} with given file name. - * - * @param filename - * to search for - * @return found List of {@link LocalArtifact}s. - */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) - public List findLocalArtifactByFilename(@NotNull final String filename) { - return localArtifactRepository.findByFilename(filename); - } - - /** - * Searches for {@link Artifact} with given {@link Identifiable}. - * - * @param id - * to search for - * @return found {@link Artifact} or null is it could not be - * found. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Artifact findArtifact(@NotNull final Long id) { - return localArtifactRepository.findOne(id); - } - - /** - * Loads {@link org.eclipse.hawkbit.artifact.server.json.model.Artifact} - * from store for given {@link LocalArtifact}. - * - * @param artifact - * to search for - * @return loaded - * {@link org.eclipse.hawkbit.artifact.server.json.model.Artifact} - * - * @throws GridFSDBFileNotFoundException - * if file could not be found in store - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DOWNLOAD_ARTIFACT + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.HAS_CONTROLLER_DOWNLOAD) - public DbArtifact loadLocalArtifactBinary(@NotNull final LocalArtifact artifact) { - final DbArtifact result = artifactRepository.getArtifactBySha1(artifact.getGridFsFileName()); - if (result == null) { - throw new GridFSDBFileNotFoundException(artifact.getGridFsFileName()); - } - - return result; - } - - /** - * Persists artifact binary as provided by given InputStream. assign the - * artifact in addition to given {@link SoftwareModule}. - * - * @param inputStream - * to read from for artifact binary - * @param moduleId - * to assign the new artifact to - * @param filename - * of the artifact - * @param overrideExisting - * 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 fails - */ - @Modifying - @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) { - return createLocalArtifact(inputStream, moduleId, filename, null, null, overrideExisting, contentType); - } - - /** - * Persists artifact binary as provided by given InputStream. assign the - * artifact in addition to given {@link SoftwareModule}. - * - * @param inputStream - * to read from for artifact binary - * @param moduleId - * to assign the new artifact to - * @param filename - * of the artifact - * @param overrideExisting - * to true if the artifact binary can be overdiden - * if it already exists - * - * @return uploaded {@link LocalArtifact} - * - * @throw ArtifactUploadFailedException if upload failes - */ - @Modifying - @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) { - return createLocalArtifact(inputStream, moduleId, filename, null, null, overrideExisting, null); - } - - /** - * Get local artifact for a base software module. - * - * @param pageReq - * Pageable - * @param swId - * software module id - * @return Page - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findLocalArtifactBySoftwareModule(@NotNull final Pageable pageReq, - @NotNull final Long swId) { - return localArtifactRepository.findBySoftwareModuleId(pageReq, swId); - } - - /** - * Find by artifact by software module id and filename. - * - * @param filename - * file name - * @param softwareModuleId - * software module id. - * @return LocalArtifact if artifact present - */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) - public List findByFilenameAndSoftwareModule(@NotNull final String filename, - @NotNull final Long softwareModuleId) { - return localArtifactRepository.findByFilenameAndSoftwareModuleId(filename, softwareModuleId); - } -} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java deleted file mode 100644 index 11879edfd..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java +++ /dev/null @@ -1,612 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository; - -import java.net.URI; -import java.util.List; -import java.util.Map; - -import javax.persistence.EntityManager; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Root; -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException; -import org.eclipse.hawkbit.repository.exception.ToManyStatusEntriesException; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.repository.model.ActionStatus; -import org.eclipse.hawkbit.repository.model.ActionStatus_; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.LocalArtifact; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.repository.model.Target_; -import org.eclipse.hawkbit.repository.model.TenantConfiguration; -import org.eclipse.hawkbit.repository.specifications.ActionSpecifications; -import org.eclipse.hawkbit.security.HawkbitSecurityProperties; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; -import org.hibernate.validator.constraints.NotEmpty; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -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; - -/** - * Service layer for all operations of the controller API (with access - * permissions only for the controller). - * - * - * - */ -@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -@Validated -@Service -public class ControllerManagement { - private static final Logger LOG = LoggerFactory.getLogger(ControllerManagement.class); - private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos"); - - public static final String SERVER_MESSAGE_PREFIX = "Update Server: "; - - @Autowired - private EntityManager entityManager; - - @Autowired - private ActionRepository actionRepository; - - @Autowired - private TargetRepository targetRepository; - - @Autowired - private TargetManagement targetManagement; - - @Autowired - private DeploymentManagement deploymentManagement; - - @Autowired - private TargetInfoRepository targetInfoRepository; - - @Autowired - private SoftwareModuleRepository softwareModuleRepository; - - @Autowired - private ActionStatusRepository actionStatusRepository; - - @Autowired - private HawkbitSecurityProperties securityProperties; - - @Autowired - private TenantConfigurationRepository tenantConfigurationRepository; - - @Autowired - private TenantConfigurationManagement tenantConfigurationManagement; - - /** - * Retrieves all {@link SoftwareModule}s which are assigned to the given - * {@link DistributionSet}. - * - * @param distributionSet - * the distribution set which should be assigned to the returned - * {@link SoftwareModule}s - * @return a list of {@link SoftwareModule}s assigned to given - * {@code distributionSet} - */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public String findPollingTime() { - final TenantConfigurationKey configurationKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; - final Class propertyType = String.class; - tenantConfigurationManagement.validateTenantConfigurationDataType(configurationKey, propertyType); - final TenantConfiguration tenantConfiguration = tenantConfigurationRepository - .findByKey(configurationKey.getKeyName()); - return tenantConfigurationManagement - .buildTenantConfigurationValueByKey(configurationKey, propertyType, tenantConfiguration).getValue(); - } - - /** - * Refreshes the time of the last time the controller has been connected to - * the server. - * - * @param targetid - * of the target to to update - * @param address - * the client address of the target, might be {@code null} - * @return the updated target - * - * @throws EntityNotFoundException - * if target with given ID could not be found - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public Target updateLastTargetQuery(@NotEmpty final String targetid, final URI address) { - final Target target = targetRepository.findByControllerId(targetid); - if (target == null) { - throw new EntityNotFoundException(targetid); - } - - return updateLastTargetQuery(target.getTargetInfo(), address).getTarget(); - } - - /** - * Retrieves last {@link UpdateAction} for a download of an artifact of - * given module and target. - * - * @param targetId - * to look for - * @param module - * that should be assigned to the target - * @return last {@link UpdateAction} for given combination - * - * @throws EntityNotFoundException - * if action for given combination could not be found - */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public Action getActionForDownloadByTargetAndSoftwareModule(@NotNull final String targetId, - @NotNull final SoftwareModule module) { - final List action = actionRepository.findActionByTargetAndSoftwareModule(targetId, module); - - if (action.isEmpty() || action.get(0).isCancelingOrCanceled()) { - throw new EntityNotFoundException( - "No assigment found for module " + module.getId() + " to target " + targetId); - } - - return action.get(0); - } - - /** - * Checks if a given target has currently or has even been assigned to the - * given artifact through the action history list. This can e.g. indicate if - * a target is allowed to download a given artifact because it has currently - * assigned or had ever been assigned to the target and so it's visible to a - * specific target e.g. for downloading. - * - * @param targetId - * the ID of the target to check - * @param localArtifact - * the artifact to verify if the given target had even been - * assigned to - * @return {@code true} if the given target has currently or had ever a - * relation to the given artifact through the action history, - * otherwise {@code false} - */ - public boolean hasTargetArtifactAssigned(@NotNull final String targetId, - @NotNull final LocalArtifact localArtifact) { - final Target target = targetRepository.findByControllerId(targetId); - if (target == null) { - return false; - } - return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(target, localArtifact)) > 0; - } - - /** - * Refreshes the time of the last time the controller has been connected to - * the server. - * - * @param target - * to update - * @param address - * the client address of the target, might be {@code null} - * @return the updated target - * - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public TargetInfo updateLastTargetQuery(@NotNull final TargetInfo target, final URI address) { - return updateTargetStatus(target, null, System.currentTimeMillis(), address); - } - - /** - * Retrieves all {@link Action}s which are active and assigned to a - * {@link Target}. - * - * @param target - * the target to retrieve the actions from - * @return a list of actions assigned to given target which are active - */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public List findActionByTargetAndActive(final Target target) { - return actionRepository.findByTargetAndActiveOrderByIdAsc(target, true); - } - - /** - * Retrieves all {@link SoftwareModule}s which are assigned to the given - * {@link DistributionSet}. - * - * @param distributionSet - * the distribution set which should be assigned to the returned - * {@link SoftwareModule}s - * @return a list of {@link SoftwareModule}s assigned to given - * {@code distributionSet} - */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public List findSoftwareModulesByDistributionSet(final DistributionSet distributionSet) { - return softwareModuleRepository.findByAssignedTo(distributionSet); - } - - /** - * Get the {@link Action} entity for given actionId with all lazy - * attributes. - * - * @param actionId - * to be id of the action - * @return the corresponding {@link Action} - */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public Action findActionWithDetails(@NotNull final Long actionId) { - return actionRepository.findById(actionId); - } - - /** - * register new target in the repository (plug-and-play). - * - * @param targetid - * reference - * @param address - * the client IP address of the target, might be {@code null} - * @return target reference - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public Target findOrRegisterTargetIfItDoesNotexist(@NotEmpty final String targetid, final URI address) { - final Specification spec = (targetRoot, query, cb) -> cb.equal(targetRoot.get(Target_.controllerId), - targetid); - - Target target = targetRepository.findOne(spec); - - if (target == null) { - target = new Target(targetid); - target.setDescription("Plug and Play target: " + targetid); - target.setName(targetid); - return targetManagement.createTarget(target, TargetUpdateStatus.REGISTERED, System.currentTimeMillis(), - address); - } - - return updateLastTargetQuery(target.getTargetInfo(), address).getTarget(); - } - - /** - * Update selective the target status of a given {@code target}. - * - * @param targetInfo - * the target to update the target status - * @param status - * the status to be set of the target. Might be {@code null} if - * the target status should not be updated - * @param lastTargetQuery - * the last target query to be set of the target. Might be - * {@code null} if the target lastTargetQuery should not be - * updated - * @param address - * the client address of the target, might be {@code null} - * @return the updated TargetInfo - */ - @Modifying - @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) { - final TargetInfo mtargetInfo = entityManager.merge(targetInfo); - if (status != null) { - mtargetInfo.setUpdateStatus(status); - } - if (lastTargetQuery != null) { - mtargetInfo.setLastTargetQuery(lastTargetQuery); - } - if (address != null) { - mtargetInfo.setAddress(address.toString()); - } - return targetInfoRepository.save(mtargetInfo); - } - - /** - * Adds an {@link ActionStatus} for a {@link UpdateAction} and cancels the - * {@link UpdateAction} if necessary. - * - * @param actionStatus - * to be updated - * @param action - * the status is for - * @return the persisted {@link Action} - * - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public Action addCancelActionStatus(@NotNull final ActionStatus actionStatus, final Action action) { - - checkForToManyStatusEntries(action); - action.setStatus(actionStatus.getStatus()); - - switch (actionStatus.getStatus()) { - case WARNING: - case ERROR: - case RUNNING: - break; - case CANCELED: - case FINISHED: - // in case of successful cancellation we also report the success at - // the canceled action itself. - actionStatus.addMessage( - ControllerManagement.SERVER_MESSAGE_PREFIX + "Cancellation completion is finished sucessfully."); - deploymentManagement.successCancellation(action); - break; - case RETRIEVED: - actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Cancellation request retrieved."); - break; - default: - } - actionRepository.save(action); - actionStatusRepository.save(actionStatus); - - return action; - } - - /** - * Updates an {@link ActionStatus} for a {@link UpdateAction}. - * - * @param actionStatus - * to be updated - * @param action - * the update is for - * @return the persisted {@link Action} - * - * @throws EntityAlreadyExistsException - * if a given entity already exists - * @throws ToManyStatusEntriesException - * if more than the allowed number of status entries are - * inserted - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public Action addUpdateActionStatus(@NotNull final ActionStatus actionStatus, final Action action) { - - if (!action.isActive()) { - LOG.debug("Update of actionStatus {} for action {} not possible since action not active anymore.", - actionStatus.getId(), action.getId()); - return action; - } - return handleAddUpdateActionStatus(actionStatus, action); - } - - /** - * Sets {@link TargetUpdateStatus} based on given {@link ActionStatus}. - * - * @param actionStatus - * @param action - * @return - */ - public Action handleAddUpdateActionStatus(final ActionStatus actionStatus, final Action action) { - LOG.debug("addUpdateActionStatus for action {}", action.getId()); - - final Action mergedAction = entityManager.merge(action); - Target mergedTarget = mergedAction.getTarget(); - // check for a potential DOS attack - checkForToManyStatusEntries(action); - - switch (actionStatus.getStatus()) { - case ERROR: - mergedTarget = deploymentManagement.updateTargetInfo(mergedTarget, TargetUpdateStatus.ERROR, false); - handleErrorOnAction(mergedAction, mergedTarget); - break; - case FINISHED: - handleFinishedAndStoreInTargetStatus(mergedTarget, mergedAction); - break; - case CANCELED: - case WARNING: - case RUNNING: - deploymentManagement.updateTargetInfo(mergedTarget, TargetUpdateStatus.PENDING, false); - break; - default: - break; - } - - actionStatusRepository.save(actionStatus); - - LOG.debug("addUpdateActionStatus {} for target {} is finished.", action.getId(), mergedTarget.getId()); - - return actionRepository.save(mergedAction); - } - - private void handleErrorOnAction(final Action mergedAction, final Target mergedTarget) { - mergedAction.setActive(false); - mergedAction.setStatus(Status.ERROR); - mergedTarget.setAssignedDistributionSet(null); - targetManagement.updateTarget(mergedTarget); - } - - private void checkForToManyStatusEntries(final Action action) { - if (securityProperties.getDos().getMaxStatusEntriesPerAction() > 0) { - - final Long statusCount = actionStatusRepository.countByAction(action); - - if (statusCount >= securityProperties.getDos().getMaxStatusEntriesPerAction()) { - LOG_DOS.error( - "Potential denial of service (DOS) attack identfied. More status entries in the system than permitted ({})!", - securityProperties.getDos().getMaxStatusEntriesPerAction()); - throw new ToManyStatusEntriesException( - String.valueOf(securityProperties.getDos().getMaxStatusEntriesPerAction())); - } - } - } - - private void handleFinishedAndStoreInTargetStatus(final Target target, final Action action) { - action.setActive(false); - action.setStatus(Status.FINISHED); - final TargetInfo targetInfo = target.getTargetInfo(); - final DistributionSet ds = entityManager.merge(action.getDistributionSet()); - targetInfo.setInstalledDistributionSet(ds); - if (target.getAssignedDistributionSet() != null && targetInfo.getInstalledDistributionSet() != null && target - .getAssignedDistributionSet().getId().equals(targetInfo.getInstalledDistributionSet().getId())) { - targetInfo.setUpdateStatus(TargetUpdateStatus.IN_SYNC); - targetInfo.setInstallationDate(System.currentTimeMillis()); - } else { - targetInfo.setUpdateStatus(TargetUpdateStatus.PENDING); - targetInfo.setInstallationDate(System.currentTimeMillis()); - } - targetInfoRepository.save(targetInfo); - entityManager.detach(ds); - } - - /** - * Updates attributes of the controller. - * - * @param targetid - * to update - * @param data - * to insert - * - * @return updated {@link Target} - * - * @throws EntityNotFoundException - * if target that has to be updated could not be found - * @throws ToManyAttributeEntriesException - * if maximum - */ - @Modifying - @NotNull - @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); - - if (target == null) { - throw new EntityNotFoundException(targetid); - } - - target.getTargetInfo().getControllerAttributes().putAll(data); - - if (target.getTargetInfo().getControllerAttributes().size() > securityProperties.getDos() - .getMaxAttributeEntriesPerTarget()) { - LOG_DOS.info("Target tries to insert more than the allowed number of entries ({}). DOS attack anticipated!", - securityProperties.getDos().getMaxAttributeEntriesPerTarget()); - throw new ToManyAttributeEntriesException( - String.valueOf(securityProperties.getDos().getMaxAttributeEntriesPerTarget())); - } - - target.getTargetInfo().setLastTargetQuery(System.currentTimeMillis()); - target.getTargetInfo().setRequestControllerAttributes(false); - return targetRepository.save(target); - } - - /** - * Registers retrieved status for given {@link Target} and {@link Action} if - * it does not exist yet. - * - * @param action - * to the handle status for - * @param target - * to the handle status for - * @param message - * for the status - * @return the update action in case the status has been changed to - * {@link Status#RETRIEVED} - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public Action registerRetrieved(final Action action, final String message) { - return handleRegisterRetrieved(action, message); - } - - /** - * Registers retrieved status for given {@link Target} and {@link Action} if - * it does not exist yet. - * - * @param action - * to the handle status for - * @param message - * for the status - * @return the updated action in case the status has been changed to - * {@link Status#RETRIEVED} - */ - public Action handleRegisterRetrieved(final Action action, final String message) { - // do a manual query with CriteriaBuilder to avoid unnecessary field - // queries and an extra - // count query made by spring-data when using pageable requests, we - // don't need an extra count - // query, we just want to check if the last action status is a retrieved - // or not. - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - final CriteriaQuery queryActionStatus = cb.createQuery(Object[].class); - final Root actionStatusRoot = queryActionStatus.from(ActionStatus.class); - final CriteriaQuery query = queryActionStatus - .multiselect(actionStatusRoot.get(ActionStatus_.id), actionStatusRoot.get(ActionStatus_.status)) - .where(cb.equal(actionStatusRoot.get(ActionStatus_.action), action)) - .orderBy(cb.desc(actionStatusRoot.get(ActionStatus_.id))); - final List resultList = entityManager.createQuery(query).setFirstResult(0).setMaxResults(1) - .getResultList(); - - // if the latest status is not in retrieve state then we add a retrieved - // state again, we want - // to document a deployment retrieved status and a cancel retrieved - // status, but multiple - // retrieves after the other we don't want to store to protect to - // overflood action status in - // case controller retrieves a action multiple times. - if (resultList.isEmpty() || resultList.get(0)[1] != Status.RETRIEVED) { - // document that the status has been retrieved - actionStatusRepository - .save(new ActionStatus(action, Status.RETRIEVED, System.currentTimeMillis(), message)); - - // don't change the action status itself in case the action is in - // canceling state otherwise - // we modify the action status and the controller won't get the - // cancel job anymore. - if (!action.isCancelingOrCanceled()) { - final Action actionMerge = entityManager.merge(action); - actionMerge.setStatus(Status.RETRIEVED); - return actionRepository.save(actionMerge); - } - } - return action; - } - - /** - * @param statusMessage - */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public void addActionStatusMessage(final ActionStatus statusMessage) { - actionStatusRepository.save(statusMessage); - } - - /** - * An direct access to the security token of an - * {@link Target#getSecurityToken()} without authorization. This is - * necessary to be able to access the security-token without any - * security-context information because the security-token is used for - * authentication. - * - * @param controllerId - * the ID of the controller to retrieve the security token for - * @return the security context of the target, in case no target exists for - * the given controllerId {@code null} is returned - */ - @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 deleted file mode 100644 index 1e58ea938..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java +++ /dev/null @@ -1,1022 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -import javax.persistence.EntityManager; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Join; -import javax.persistence.criteria.JoinType; -import javax.persistence.criteria.ListJoin; -import javax.persistence.criteria.Root; -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.Constants; -import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent; -import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent; -import org.eclipse.hawkbit.eventbus.event.TargetInfoUpdateEvent; -import org.eclipse.hawkbit.executor.AfterTransactionCommitExecutor; -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException; -import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.Action.ActionType; -import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.repository.model.ActionStatus; -import org.eclipse.hawkbit.repository.model.ActionWithStatusCount; -import org.eclipse.hawkbit.repository.model.Action_; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.DistributionSet_; -import org.eclipse.hawkbit.repository.model.Rollout; -import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.Rollout_; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.repository.specifications.TargetSpecifications; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.hibernate.validator.constraints.NotEmpty; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.data.domain.AuditorAware; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -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.collect.Lists; -import com.google.common.eventbus.EventBus; - -/** - * Business service facade for managing all deployment related data and actions. - * - * - */ -@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -@Validated -@Service -public class DeploymentManagement { - private static final Logger LOG = LoggerFactory.getLogger(DeploymentManagement.class); - - @Autowired - private EntityManager entityManager; - - @Autowired - private ActionRepository actionRepository; - - @Autowired - private DistributionSetRepository distributoinSetRepository; - - @Autowired - private SoftwareModuleRepository softwareModuleRepository; - - @Autowired - private TargetRepository targetRepository; - - @Autowired - private ActionStatusRepository actionStatusRepository; - - @Autowired - private TargetManagement targetManagement; - - @Autowired - private TargetInfoRepository targetInfoRepository; - - @Autowired - private AuditorAware auditorProvider; - - @Autowired - private EventBus eventBus; - - @Autowired - private AfterTransactionCommitExecutor afterCommit; - - @Autowired - private SystemSecurityContext systemSecurityContext; - - /** - * method assigns the {@link DistributionSet} to all {@link Target}s. - * - * @param pset - * {@link DistributionSet} which is assigned to the - * {@link Target}s - * @param targets - * the {@link Target}s which should obtain the - * {@link DistributionSet} - * - * @return the changed targets - * - * @throw IncompleteDistributionSetException if mandatory - * {@link SoftwareModuleType} are not assigned as define by the - * {@link DistributionSetType}. * - */ - @Transactional(isolation = Isolation.READ_COMMITTED) - @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) - @CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true) - public DistributionSetAssignmentResult assignDistributionSet(@NotNull final DistributionSet pset, - @NotEmpty final List targets) { - - return assignDistributionSetByTargetId(pset, - targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()), - ActionType.FORCED, Action.NO_FORCE_TIME); - - } - - /** - * method assigns the {@link DistributionSet} to all {@link Target}s by - * their IDs. - * - * @param dsID - * {@link DistributionSet} which is assigned to the - * {@link Target}s - * @param targetIDs - * IDs of the {@link Target}s which should obtain the - * {@link DistributionSet} - * - * @return the changed targets - * - * @throws EntityNotFoundException - * if {@link DistributionSet} does not exist. - * - * @throw IncompleteDistributionSetException if mandatory - * {@link SoftwareModuleType} are not assigned as define by the - * {@link DistributionSetType}. - */ - @Modifying - @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, - @NotEmpty final String... targetIDs) { - return assignDistributionSet(dsID, ActionType.FORCED, Action.NO_FORCE_TIME, targetIDs); - } - - /** - * method assigns the {@link DistributionSet} to all {@link Target}s by - * their IDs with a specific {@link ActionType} and {@code forcetime}. - * - * @param dsID - * the ID of the distribution set to assign - * @param actionType - * the type of the action to apply on the assignment - * @param forcedTimestamp - * the time when the action should be forced, only necessary for - * {@link ActionType#TIMEFORCED} - * @param targetIDs - * the IDs of the target to assign the distribution set - * @return the assignment result - * - * @throw IncompleteDistributionSetException if mandatory - * {@link SoftwareModuleType} are not assigned as define by the - * {@link DistributionSetType}. - */ - @Modifying - @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) - .map(t -> new TargetWithActionType(t, actionType, forcedTimestamp)).collect(Collectors.toList())); - } - - /** - * method assigns the {@link DistributionSet} to all {@link Target}s by - * their IDs with a specific {@link ActionType} and {@code forcetime}. - * - * @param dsID - * the ID of the distribution set to assign - * @param targets - * a list of all targets and their action type - * @return the assignment result - * - * @throw IncompleteDistributionSetException if mandatory - * {@link SoftwareModuleType} are not assigned as define by the - * {@link DistributionSetType}. - */ - @Modifying - @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, - final List targets) { - final DistributionSet set = distributoinSetRepository.findOne(dsID); - if (set == null) { - throw new EntityNotFoundException( - String.format("no %s with id %d found", DistributionSet.class.getSimpleName(), dsID)); - } - - return assignDistributionSetToTargets(set, targets, null, null); - } - - /** - * method assigns the {@link DistributionSet} to all {@link Target}s by - * their IDs with a specific {@link ActionType} and {@code forcetime}. - * - * @param dsID - * the ID of the distribution set to assign - * @param targets - * a list of all targets and their action type - * @param rollout - * the rollout for this assignment - * @param rolloutGroup - * the rollout group for this assignment - * @return the assignment result - * - * @throw IncompleteDistributionSetException if mandatory - * {@link SoftwareModuleType} are not assigned as define by the - * {@link DistributionSetType}. - */ - @Modifying - @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, - final List targets, final Rollout rollout, final RolloutGroup rolloutGroup) { - final DistributionSet set = distributoinSetRepository.findOne(dsID); - if (set == null) { - throw new EntityNotFoundException( - String.format("no %s with id %d found", DistributionSet.class.getSimpleName(), dsID)); - } - - return assignDistributionSetToTargets(set, targets, rollout, rolloutGroup); - } - - /** - * method assigns the {@link DistributionSet} to all {@link Target}s by - * their IDs with a specific {@link ActionType} and {@code forcetime}. - * - * @param dsID - * the ID of the distribution set to assign - * @param targets - * a list of all targets and their action type - * @param rollout - * the rollout for this assignment - * @param rolloutGroup - * the rollout group for this assignment - * @return the assignment result - * - * @throw IncompleteDistributionSetException if mandatory - * {@link SoftwareModuleType} are not assigned as define by the - * {@link DistributionSetType}. - */ - private DistributionSetAssignmentResult assignDistributionSetToTargets(@NotNull final DistributionSet set, - final List targetsWithActionType, final Rollout rollout, - final RolloutGroup rolloutGroup) { - - if (!set.isComplete()) { - throw new IncompleteDistributionSetException( - "Distribution set of type " + set.getType().getKey() + " is incomplete: " + set.getId()); - } - - final List controllerIDs = targetsWithActionType.stream().map(TargetWithActionType::getTargetId) - .collect(Collectors.toList()); - - LOG.debug("assignDistribution({}) to {} targets", set, controllerIDs.size()); - - final Map targetsWithActionMap = targetsWithActionType.stream() - .collect(Collectors.toMap(TargetWithActionType::getTargetId, Function.identity())); - - // split tIDs length into max entries in-statement because many database - // have constraint of max entries in in-statements e.g. Oracle with - // maximum 1000 elements, so we need to split the entries here and - // execute multiple statements we take the target only into account if - // the requested operation is no duplicate of a previous one - final List targets = Lists.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT).stream() - .map(ids -> targetRepository - .findAll(TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, set.getId()))) - .flatMap(t -> t.stream()).collect(Collectors.toList()); - - if (targets.isEmpty()) { - // detaching as it is not necessary to persist the set itself - entityManager.detach(set); - // return with nothing as all targets had the DS already assigned - return new DistributionSetAssignmentResult(Collections.emptyList(), 0, targetsWithActionType.size(), - Collections.emptyList(), targetManagement); - } - - final List> targetIds = Lists.partition( - targets.stream().map(Target::getId).collect(Collectors.toList()), Constants.MAX_ENTRIES_IN_STATEMENT); - - // override all active actions and set them into canceling state, we - // need to remember which one we have been switched to canceling state - // because for targets which we have changed to canceling we don't want - // to publish the new action update event. - final Set targetIdsCancellList = new HashSet<>(); - targetIds.forEach(ids -> targetIdsCancellList.addAll(overrideObsoleteUpdateActions(ids))); - - // cancel all scheduled actions which are in-active, these actions were - // not active before and the manual assignment which has been done - // cancels the - targetIds.forEach(tIds -> actionRepository.switchStatus(Status.CANCELED, tIds, false, Status.SCHEDULED)); - - // set assigned distribution set and TargetUpdateStatus - final String currentUser; - if (auditorProvider != null) { - currentUser = auditorProvider.getCurrentAuditor(); - } else { - currentUser = null; - } - - targetIds.forEach(tIds -> targetRepository.setAssignedDistributionSet(set, System.currentTimeMillis(), - currentUser, tIds)); - targetIds.forEach(tIds -> targetInfoRepository.setTargetUpdateStatus(TargetUpdateStatus.PENDING, tIds)); - final Map targetIdsToActions = actionRepository - .save(targets.stream().map(t -> createTargetAction(targetsWithActionMap, t, set, rollout, rolloutGroup)) - .collect(Collectors.toList())) - .stream().collect(Collectors.toMap(a -> a.getTarget().getControllerId(), Function.identity())); - - // create initial action status when action is created so we remember - // the initial running status because we will change the status - // of the action itself and with this action status we have a nicer - // action history. - targetIdsToActions.values().forEach(action -> { - final ActionStatus actionStatus = new ActionStatus(); - actionStatus.setAction(action); - actionStatus.setOccurredAt(action.getCreatedAt()); - actionStatus.setStatus(Status.RUNNING); - actionStatusRepository.save(actionStatus); - }); - - // flush to get action IDs - entityManager.flush(); - // collect updated target and actions IDs in order to return them - final DistributionSetAssignmentResult result = new DistributionSetAssignmentResult( - targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()), targets.size(), - controllerIDs.size() - targets.size(), - targetIdsToActions.values().stream().map(Action::getId).collect(Collectors.toList()), targetManagement); - - LOG.debug("assignDistribution({}) finished {}", set, result); - - final List softwareModules = softwareModuleRepository.findByAssignedTo(set); - - // detaching as it is not necessary to persist the set itself - entityManager.detach(set); - - sendDistributionSetAssignmentEvent(targets, targetIdsCancellList, targetIdsToActions, softwareModules); - - return result; - } - - private void sendDistributionSetAssignmentEvent(final List targets, final Set targetIdsCancellList, - final Map targetIdsToActions, final List softwareModules) { - targets.stream().filter(t -> !!!targetIdsCancellList.contains(t.getId())) - .forEach(t -> assignDistributionSetEvent(t, targetIdsToActions.get(t.getControllerId()).getId(), - softwareModules)); - } - - 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()); - actionForTarget.setForcedTime(targetWithActionType.getForceTime()); - actionForTarget.setActive(true); - actionForTarget.setStatus(Status.RUNNING); - actionForTarget.setTarget(target); - actionForTarget.setDistributionSet(set); - actionForTarget.setRollout(rollout); - actionForTarget.setRolloutGroup(rolloutGroup); - return actionForTarget; - } - - /** - * Sends the {@link TargetAssignDistributionSetEvent} for a specific target - * to the {@link EventBus}. - * - * @param target - * the Target which has been assigned to a distribution set - * @param actionId - * the action id of the assignment - * @param softwareModules - * the software modules which have been assigned - */ - private void assignDistributionSetEvent(final Target target, final Long actionId, - final List softwareModules) { - target.getTargetInfo().setUpdateStatus(TargetUpdateStatus.PENDING); - final String targetSecurityToken = systemSecurityContext.runAsSystem(() -> { - return target.getSecurityToken(); - }); - afterCommit.afterCommit(() -> { - eventBus.post(new TargetInfoUpdateEvent(target.getTargetInfo())); - eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(), - target.getControllerId(), actionId, softwareModules, target.getTargetInfo().getAddress(), - targetSecurityToken)); - }); - } - - /** - * Removes {@link UpdateAction}s that are no longer necessary and sends - * cancellations to the controller. - * - * @param myTarget - * to override {@link UpdateAction}s - */ - private Set overrideObsoleteUpdateActions(final List targetsIds) { - - final Set cancelledTargetIds = new HashSet<>(); - - // Figure out if there are potential target/action combinations that - // need to be considered - // for cancelation - final List activeActions = actionRepository - .findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetRequiredMigrationStep(targetsIds, - Action.Status.CANCELING); - activeActions.forEach(action -> { - action.setStatus(Status.CANCELING); - // document that the status has been retrieved - - actionStatusRepository.save(new ActionStatus(action, Status.CANCELING, System.currentTimeMillis(), - "manual cancelation requested")); - - cancelAssignDistributionSetEvent(action.getTarget(), action.getId()); - - cancelledTargetIds.add(action.getTarget().getId()); - }); - - actionRepository.save(activeActions); - - return cancelledTargetIds; - - } - - private DistributionSetAssignmentResult assignDistributionSetByTargetId(@NotNull final DistributionSet set, - @NotEmpty final List tIDs, final ActionType actionType, final long forcedTime) { - - return assignDistributionSetToTargets(set, tIDs.stream() - .map(t -> new TargetWithActionType(t, actionType, forcedTime)).collect(Collectors.toList()), null, - null); - - } - - /** - * Internal helper method used only inside service level. As a result is no - * additional security necessary. - * - * @param target - * to update - * @param status - * of the target - * @param setInstalledDate - * to set - * - * @return updated target - */ - Target updateTargetInfo(@NotNull final Target target, @NotNull final TargetUpdateStatus status, - final boolean setInstalledDate) { - final TargetInfo ts = target.getTargetInfo(); - ts.setUpdateStatus(status); - - if (setInstalledDate) { - ts.setInstallationDate(System.currentTimeMillis()); - } - targetInfoRepository.save(ts); - return entityManager.merge(target); - } - - /** - * Cancels given {@link Action} for given {@link Target}. The method will - * immediately add a {@link ActionStatus.Status#CANCELED} status to the - * action. However, it might be possible that the controller will continue - * to work on the cancellation. - * - * @param action - * to be canceled - * @param target - * for which the action needs cancellation - * - * @return generated {@link CancelAction} or null if not in - * {@link Target#getActiveActions()}. - * @throws CancelActionNotAllowedException - * in case the given action is not active or is already a cancel - * action - */ - @Modifying - @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); - if (action.isCancelingOrCanceled()) { - throw new CancelActionNotAllowedException("Actions in canceling or canceled state cannot be canceled"); - } - final Action myAction = entityManager.merge(action); - - if (myAction.isActive()) { - LOG.debug("action ({}) was still active. Change to {}.", action, Status.CANCELING); - myAction.setStatus(Status.CANCELING); - - // document that the status has been retrieved - actionStatusRepository.save(new ActionStatus(myAction, Status.CANCELING, System.currentTimeMillis(), - "manual cancelation requested")); - final Action saveAction = actionRepository.save(myAction); - cancelAssignDistributionSetEvent(target, myAction.getId()); - - return saveAction; - } else { - throw new CancelActionNotAllowedException( - "Action [id: " + action.getId() + "] is not active and cannot be canceled"); - } - } - - /** - * Sends the {@link CancelTargetAssignmentEvent} for a specific target to - * the {@link EventBus}. - * - * @param target - * the Target which has been assigned to a distribution set - * @param actionId - * the action id of the assignment - */ - private void cancelAssignDistributionSetEvent(final Target target, final Long actionId) { - afterCommit.afterCommit(() -> eventBus.post(new CancelTargetAssignmentEvent(target.getOptLockRevision(), - target.getTenant(), target.getControllerId(), actionId, target.getTargetInfo().getAddress()))); - } - - /** - * Force cancels given {@link Action} for given {@link Target}. Force - * canceling means that the action is marked as canceled on the SP server - * and a cancel request is sent to the target. But however it's not tracked, - * if the targets handles the cancel request or not. - * - * @param action - * to be canceled - * @param target - * for which the action needs cancellation - * - * @return generated {@link CancelAction} or null if not in - * {@link Target#getActiveActions()}. - * @throws CancelActionNotAllowedException - * in case the given action is not active - */ - @Modifying - @Transactional(isolation = Isolation.READ_COMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - public Action forceQuitAction(@NotNull final Action action) { - final Action mergedAction = entityManager.merge(action); - - if (!mergedAction.isCancelingOrCanceled()) { - throw new ForceQuitActionNotAllowedException( - "Action [id: " + action.getId() + "] is not canceled yet and cannot be force quit"); - } - - if (!mergedAction.isActive()) { - throw new ForceQuitActionNotAllowedException( - "Action [id: " + action.getId() + "] is not active and cannot be force quit"); - } - - LOG.warn("action ({}) was still activ and has been force quite.", action); - - // document that the status has been retrieved - actionStatusRepository.save(new ActionStatus(mergedAction, Status.CANCELED, System.currentTimeMillis(), - "A force quit has been performed.")); - - successCancellation(mergedAction); - - return actionRepository.save(mergedAction); - } - - /** - * Creates an action entry into the action repository. In case of existing - * scheduled actions the scheduled actions gets canceled. A scheduled action - * is created in-active. - * - * @param targets - * the targets to create scheduled actions for - * @param distributionSet - * the distribution set for the actions - * @param actionType - * the action type for the action - * @param forcedTime - * the forcedTime of the action - * @param rollout - * the rollout for this action - * @param rolloutGroup - * the rolloutgroup for this action - */ - @Modifying - @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, - final RolloutGroup rolloutGroup) { - // cancel all current scheduled actions for this target. E.g. an action - // is already scheduled and a next action is created then cancel the - // current scheduled action to cancel. E.g. a new scheduled action is - // created. - final List targetIds = targets.stream().map(t -> t.getId()).collect(Collectors.toList()); - actionRepository.switchStatus(Action.Status.CANCELED, targetIds, false, Action.Status.SCHEDULED); - targets.forEach(target -> { - final Action action = new Action(); - action.setTarget(target); - action.setActive(false); - action.setDistributionSet(distributionSet); - action.setActionType(actionType); - action.setForcedTime(forcedTime); - action.setStatus(Status.SCHEDULED); - action.setRollout(rollout); - action.setRolloutGroup(rolloutGroup); - actionRepository.save(action); - }); - } - - /** - * Starting an action which is scheduled, e.g. in case of rollout a - * scheduled action must be started now. - * - * @param action - * the action to start now. - * @return the action which has been started - */ - @Modifying - @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) { - - final Action mergedAction = entityManager.merge(action); - final Target mergedTarget = entityManager.merge(action.getTarget()); - - // check if we need to override running update actions - final Set overrideObsoleteUpdateActions = overrideObsoleteUpdateActions( - Collections.singletonList(action.getTarget().getId())); - - final boolean hasDistributionSetAlreadyAssigned = targetRepository - .count(TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot( - Collections.singletonList(mergedTarget.getControllerId()), - action.getDistributionSet().getId())) == 0; - if (hasDistributionSetAlreadyAssigned) { - // the target has already the distribution set assigned, we don't - // need to start the scheduled action, just finished it. - mergedAction.setStatus(Status.FINISHED); - mergedAction.setActive(false); - return actionRepository.save(mergedAction); - } - - mergedAction.setActive(true); - mergedAction.setStatus(Status.RUNNING); - final Action savedAction = actionRepository.save(mergedAction); - - final ActionStatus actionStatus = new ActionStatus(); - actionStatus.setAction(action); - actionStatus.setOccurredAt(action.getCreatedAt()); - actionStatus.setStatus(Status.RUNNING); - actionStatusRepository.save(actionStatus); - - mergedTarget.setAssignedDistributionSet(action.getDistributionSet()); - final TargetInfo targetInfo = mergedTarget.getTargetInfo(); - targetInfo.setUpdateStatus(TargetUpdateStatus.PENDING); - targetRepository.save(mergedTarget); - targetInfoRepository.save(targetInfo); - - // in case we canceled an action before for this target, then don't fire - // assignment event - if (!overrideObsoleteUpdateActions.contains(savedAction.getId())) { - final List softwareModules = softwareModuleRepository - .findByAssignedTo(action.getDistributionSet()); - // send distribution set assignment event - - assignDistributionSetEvent(mergedAction.getTarget(), mergedAction.getId(), softwareModules); - } - return savedAction; - } - - /** - * Get the {@link Action} entity for given actionId. - * - * @param actionId - * to be id of the action - * @return the corresponding {@link Action} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Action findAction(@NotNull final Long actionId) { - return actionRepository.findOne(actionId); - } - - /** - * Get the {@link Action} entity for given actionId with all lazy attributes - * (i.e. distributionSet, target, target.assignedDs). - * - * @param actionId - * to be id of the action - * @return the corresponding {@link Action} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Action findActionWithDetails(@NotNull final Long actionId) { - return actionRepository.findById(actionId); - } - - /** - * Retrieves all {@link Action}s of a specific target. - * - * @param pageable - * pagination parameter - * @param target - * of which the actions have to be searched - * @return a paged list of actions associated with the given target - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Slice findActionsByTarget(final Pageable pageable, final Target target) { - return actionRepository.findByTarget(pageable, target); - } - - /** - * Retrieves all {@link Action}s of a specific target ordered by action ID. - * - * @param target - * the target associated with the actions - * @return a list of actions associated with the given target ordered by - * action ID - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findActionsByTarget(final Target target) { - return actionRepository.findByTarget(target); - } - - /** - * Retrieves all {@link Action}s of a specific target ordered by action ID. - * - * @param target - * the target associated with the actions - * @return a list of actions associated with the given target ordered by - * action ID - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findActionsWithStatusCountByTargetOrderByIdDesc(final Target target) { - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - final CriteriaQuery query = cb.createQuery(ActionWithStatusCount.class); - final Root actionRoot = query.from(Action.class); - final ListJoin actionStatusJoin = actionRoot.join(Action_.actionStatus, JoinType.LEFT); - final Join actionDsJoin = actionRoot.join(Action_.distributionSet); - final Join actionRolloutJoin = actionRoot.join(Action_.rollout, JoinType.LEFT); - - final CriteriaQuery multiselect = query.distinct(true).multiselect( - actionRoot.get(Action_.id), actionRoot.get(Action_.actionType), actionRoot.get(Action_.active), - actionRoot.get(Action_.forcedTime), actionRoot.get(Action_.status), actionRoot.get(Action_.createdAt), - actionRoot.get(Action_.lastModifiedAt), actionDsJoin.get(DistributionSet_.id), - actionDsJoin.get(DistributionSet_.name), actionDsJoin.get(DistributionSet_.version), - cb.count(actionStatusJoin), actionRolloutJoin.get(Rollout_.name)); - multiselect.where(cb.equal(actionRoot.get(Action_.target), target)); - multiselect.orderBy(cb.desc(actionRoot.get(Action_.id))); - multiselect.groupBy(actionRoot.get(Action_.id)); - return entityManager.createQuery(multiselect).getResultList(); - } - - /** - * Retrieves all {@link Action}s assigned to a specific {@link Target} and a - * given specification. - * - * @param specifiction - * the specification to narrow down the search - * @param target - * the target which must be assigned to the actions - * @param pageable - * the page request - * @return a slice of actions assigned to the specific target and the - * specification - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Slice findActionsByTarget(final Specification specifiction, final Target target, - final Pageable pageable) { - - return actionRepository.findAll((Specification) (root, query, cb) -> cb - .and(specifiction.toPredicate(root, query, cb), cb.equal(root.get(Action_.target), target)), pageable); - } - - /** - * Retrieves all {@link Action}s which are referring the given - * {@link Target}. - * - * @param foundTarget - * the target to find actions for - * @param pageable - * the pageable request to limit, sort the actions - * @return a slice of actions found for a specific target - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Slice findActionsByTarget(final Target foundTarget, final Pageable pageable) { - return actionRepository.findByTarget(pageable, foundTarget); - } - - /** - * Retrieves all active {@link Action}s of a specific target ordered by - * action ID. - * - * @param pageable - * the pagination parameter - * @param target - * the target associated with the actions - * @return a paged list of actions associated with the given target - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Page findActiveActionsByTarget(final Pageable pageable, final Target target) { - return actionRepository.findByActiveAndTarget(pageable, target, true); - } - - /** - * Retrieves all active {@link Action}s of a specific target ordered by - * action ID. - * - * @param target - * the target associated with the actions - * @return a list of actions associated with the given target - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findActiveActionsByTarget(final Target target) { - return actionRepository.findByActiveAndTarget(target, true); - } - - /** - * Retrieves all inactive {@link Action}s of a specific target ordered by - * action ID. - * - * @param target - * the target associated with the actions - * @return a list of actions associated with the given target - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findInActiveActionsByTarget(final Target target) { - return actionRepository.findByActiveAndTarget(target, false); - } - - /** - * Retrieves all inactive {@link Action}s of a specific target ordered by - * action ID. - * - * @param pageable - * the pagination parameter - * @param target - * the target associated with the actions - * @return a paged list of actions associated with the given target - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Page findInActiveActionsByTarget(final Pageable pageable, final Target target) { - return actionRepository.findByActiveAndTarget(pageable, target, false); - } - - /** - * counts all actions associated to a specific target. - * - * @param target - * the target associated to the actions to count - * @return the count value of found actions associated to the target - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Long countActionsByTarget(@NotNull final Target target) { - return actionRepository.countByTarget(target); - } - - /** - * counts all actions associated to a specific target. - * - * @param spec - * the specification to filter the count result - * @param target - * the target associated to the actions to count - * @return the count value of found actions associated to the target - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Long countActionsByTarget(@NotNull final Specification spec, @NotNull final Target target) { - return actionRepository.count((root, query, cb) -> cb.and(spec.toPredicate(root, query, cb), - cb.equal(root.get(Action_.target), target))); - } - - /** - * Updates a {@link TargetAction} and forces the {@link TargetAction} if - * it's not already forced. - * - * @param targetId - * the ID of the target - * @param actionId - * the ID of the action - * @return the updated or the found {@link TargetAction} - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - public Action forceTargetAction(final Long actionId) { - final Action action = actionRepository.findOne(actionId); - if (action != null && !action.isForced()) { - action.setActionType(ActionType.FORCED); - return actionRepository.save(action); - } - return action; - } - - /** - * Retrieves all the {@link ActionStatus} entries of the given - * {@link Action} and {@link Target}. - * - * @param pageReq - * pagination parameter - * @param action - * to be filtered on - * @param withMessages - * to true if {@link ActionStatus#getMessages()} - * need to be fetched. - * @return the corresponding {@link Page} of {@link ActionStatus} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Page findActionStatusByAction(final Pageable pageReq, final Action action, - final boolean withMessages) { - if (withMessages) { - return actionStatusRepository.getByAction(pageReq, action); - } else { - return actionStatusRepository.findByAction(pageReq, action); - } - } - - /** - * This method is called, when cancellation has been successful. It sets the - * action to canceled, resets the meta data of the target and in case there - * is a new action this action is triggered. - * - * @param action - * the action which is set to canceled - */ - void successCancellation(final Action action) { - - // set action inactive - action.setActive(false); - action.setStatus(Status.CANCELED); - - final Target target = action.getTarget(); - final List nextActiveActions = actionRepository.findByTargetAndActiveOrderByIdAsc(target, true).stream() - .filter(a -> !a.getId().equals(action.getId())).collect(Collectors.toList()); - - if (nextActiveActions.isEmpty()) { - target.setAssignedDistributionSet(target.getTargetInfo().getInstalledDistributionSet()); - updateTargetInfo(target, TargetUpdateStatus.IN_SYNC, false); - } else { - target.setAssignedDistributionSet(nextActiveActions.get(0).getDistributionSet()); - } - targetManagement.updateTarget(target); - } - - /** - * Retrieving all actions referring to a given rollout with a specific - * action as parent reference and a specific status. - * - * Finding all actions of a specific rolloutgroup parent relation. - * - * @param rollout - * the rollout the actions belong to - * @param rolloutGroupParent - * 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 - * rollout group in a specific status - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_SYSTEM_CODE) - public List findActionsByRolloutGroupParentAndStatus(final Rollout rollout, - final RolloutGroup rolloutGroupParent, final Action.Status actionStatus) { - return actionRepository.findByRolloutAndRolloutGroupParentAndStatus(rollout, rolloutGroupParent, actionStatus); - } - - /** - * Retrieves all actions for a specific rollout and in a specific status. - * - * @param rollout - * the rollout the actions beglong to - * @param actionStatus - * the status of the actions - * @return the actions referring a specific rollout an in a specific status - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findActionsByRolloutAndStatus(final Rollout rollout, final Action.Status actionStatus) { - return actionRepository.findByRolloutAndStatus(rollout, actionStatus); - } -} 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 deleted file mode 100644 index db1ade60e..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java +++ /dev/null @@ -1,1112 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.persistence.Entity; -import javax.persistence.EntityManager; -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.eventbus.event.DistributionSetTagAssigmentResultEvent; -import org.eclipse.hawkbit.executor.AfterTransactionCommitExecutor; -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.DistributionSetFilter.DistributionSetFilterBuilder; -import org.eclipse.hawkbit.repository.exception.DistributionSetCreationFailedMissingMandatoryModuleException; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.exception.EntityLockedException; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; -import org.eclipse.hawkbit.repository.model.DistributionSetMetadata_; -import org.eclipse.hawkbit.repository.model.DistributionSetTag; -import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; -import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.DistributionSetTypeElement; -import org.eclipse.hawkbit.repository.model.DistributionSet_; -import org.eclipse.hawkbit.repository.model.DsMetadataCompositeKey; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.model.Tag; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.specifications.DistributionSetSpecification; -import org.eclipse.hawkbit.repository.specifications.DistributionSetTypeSpecification; -import org.eclipse.hawkbit.repository.specifications.SpecificationsBuilder; -import org.hibernate.validator.constraints.NotEmpty; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -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.base.Strings; -import com.google.common.eventbus.EventBus; - -/** - * Business facade for managing the {@link DistributionSet}s. - * - */ -@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -@Validated -@Service -public class DistributionSetManagement { - - @Autowired - private EntityManager entityManager; - - @Autowired - private DistributionSetRepository distributionSetRepository; - - @Autowired - private TagManagement tagManagement; - - @Autowired - private SystemManagement systemManagement; - - @Autowired - private DistributionSetTypeRepository distributionSetTypeRepository; - - @Autowired - private DistributionSetMetadataRepository distributionSetMetadataRepository; - - @Autowired - private ActionRepository actionRepository; - - @Autowired - private EventBus eventBus; - - @Autowired - private AfterTransactionCommitExecutor afterCommit; - - /** - * Find {@link DistributionSet} based on given ID including (lazy loaded) - * details, e.g. {@link DistributionSet#getAgentHub()}. - * - * Note: for performance reasons it is recommended to use - * {@link #findDistributionSetById(Long)} if details are not necessary. - * - * @param distid - * to look for. - * @return {@link DistributionSet} or null if it does not exist - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public DistributionSet findDistributionSetByIdWithDetails(@NotNull final Long distid) { - return distributionSetRepository.findOne(DistributionSetSpecification.byId(distid)); - } - - /** - * Find {@link DistributionSet} based on given ID without details, e.g. - * {@link DistributionSet#getAgentHub()}. - * - * @param distid - * to look for. - * @return {@link DistributionSet} or null if it does not exist - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public DistributionSet findDistributionSetById(@NotNull final Long distid) { - return distributionSetRepository.findOne(distid); - } - - /** - * {@link Entity} based method call for - * {@link #toggleTagAssignment(Collection, String)}. - * - * @param sets - * to toggle for - * @param tag - * to toggle - * @return {@link DistributionSetTagAssignmentResult} with all meta data of - * the assignment outcome. - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty final List sets, - @NotNull final DistributionSetTag tag) { - return toggleTagAssignment(sets.stream().map(ds -> ds.getId()).collect(Collectors.toList()), tag.getName()); - } - - /** - * Toggles {@link DistributionSetTag} assignment to given - * {@link DistributionSet}s by means that if some (or all) of the targets in - * the list have the {@link Tag} not yet assigned, they will be. If all of - * theme have the tag already assigned they will be removed instead. - * - * @param dsIds - * to toggle for - * @param tagName - * to toggle - * @return {@link DistributionSetTagAssignmentResult} with all meta data of - * the assignment outcome. - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty final Collection dsIds, - @NotNull final String tagName) { - - final Iterable sets = findDistributionSetListWithDetails(dsIds); - final DistributionSetTag myTag = tagManagement.findDistributionSetTag(tagName); - - DistributionSetTagAssignmentResult result; - final List toBeChangedDSs = new ArrayList<>(); - for (final DistributionSet set : sets) { - if (set.getTags().add(myTag)) { - toBeChangedDSs.add(set); - } - } - - // un-assignment case - if (toBeChangedDSs.isEmpty()) { - for (final DistributionSet set : sets) { - if (set.getTags().remove(myTag)) { - toBeChangedDSs.add(set); - } - } - result = new DistributionSetTagAssignmentResult(dsIds.size() - toBeChangedDSs.size(), 0, - toBeChangedDSs.size(), Collections.emptyList(), distributionSetRepository.save(toBeChangedDSs), - myTag); - } else { - result = new DistributionSetTagAssignmentResult(dsIds.size() - toBeChangedDSs.size(), toBeChangedDSs.size(), - 0, distributionSetRepository.save(toBeChangedDSs), Collections.emptyList(), myTag); - } - - final DistributionSetTagAssignmentResult resultAssignment = result; - afterCommit.afterCommit(() -> eventBus.post(new DistributionSetTagAssigmentResultEvent(resultAssignment))); - - // no reason to persist the tag - entityManager.detach(myTag); - return result; - } - - /** - * Retrieves {@link DistributionSet} List including details information, - * i.e. @link BaseSoftwareModule}s and {@link DistributionSetTag}s. - * - * @param distributionIdSet - * List of {@link DistributionSet} IDs to be found - * @return the found {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public List findDistributionSetListWithDetails( - @NotEmpty final Collection distributionIdSet) { - return distributionSetRepository.findAll(DistributionSetSpecification.byIds(distributionIdSet)); - } - - /** - * Updates existing {@link DistributionSet}. - * - * @param ds - * to update - * @return the saved {@link Entity}. - * @throws NullPointerException - * of {@link DistributionSet#getId()} is null - * @throw DataDependencyViolationException in case of illegal update - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public DistributionSet updateDistributionSet(@NotNull final DistributionSet ds) { - checkNotNull(ds.getId()); - final DistributionSet persisted = findDistributionSetByIdWithDetails(ds.getId()); - checkDistributionSetSoftwareModulesIsAllowedToModify(ds, persisted.getModules()); - return distributionSetRepository.save(ds); - } - - /** - *

- * {@link DistributionSet} can be deleted/erased from the repository if they - * have never been assigned to any {@link UpdateAction} or {@link Target}. - *

- * - *

- * If they have been assigned that need to be marked as deleted which as a - * result means that they cannot be assigned anymore to any targets. (define - * e.g. findByDeletedFalse()) - *

- * - * @param set - * to delete - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - public void deleteDistributionSet(@NotNull final DistributionSet set) { - deleteDistributionSet(set.getId()); - } - - /** - * Deleted {@link DistributionSet}s by their IDs. That is either a soft - * delete of the entities have been linked to an {@link UpdateAction} before - * or a hard delete if not. - * - * @param distributionSetIDs - * to be deleted - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - public void deleteDistributionSet(@NotEmpty final Long... distributionSetIDs) { - final List toHardDelete = new ArrayList<>(); - - final List assigned = distributionSetRepository.findAssignedDistributionSetsById(distributionSetIDs); - - // soft delete assigned - if (!assigned.isEmpty()) { - distributionSetRepository.deleteDistributionSet(assigned.toArray(new Long[assigned.size()])); - } - - // mark the rest as hard delete - for (final Long setId : distributionSetIDs) { - if (!assigned.contains(setId)) { - toHardDelete.add(setId); - } - } - - // hard delete the rest if exixts - if (!toHardDelete.isEmpty()) { - // don't give the delete statement an empty list, JPA/Oracle cannot - // handle the empty list - distributionSetRepository.deleteByIdIn(toHardDelete); - } - } - - /** - * Creates a new {@link DistributionSet}. - * - * @param dSet - * {@link DistributionSet} to be created - * @return the new persisted {@link DistributionSet} - * - * @throws EntityAlreadyExistsException - * if a given entity already exists - * @throws DistributionSetCreationFailedMissingMandatoryModuleException - * is {@link DistributionSet} does not contain mandatory - * {@link SoftwareModule}s. - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - public DistributionSet createDistributionSet(@NotNull final DistributionSet dSet) { - prepareDsSave(dSet); - if (dSet.getType() == null) { - dSet.setType(systemManagement.getTenantMetadata().getDefaultDsType()); - } - return distributionSetRepository.save(dSet); - } - - private void prepareDsSave(final DistributionSet dSet) { - if (dSet.getId() != null) { - throw new EntityAlreadyExistsException("Parameter seems to be an existing, already persisted entity"); - } - - if (distributionSetRepository.countByNameAndVersion(dSet.getName(), dSet.getVersion()) > 0) { - throw new EntityAlreadyExistsException("DistributionSet with that name and version already exists."); - } - - } - - /** - * Creates multiple {@link DistributionSet}s. - * - * @param distributionSets - * to be created - * @return the new {@link DistributionSet}s - * @throws EntityAlreadyExistsException - * if a given entity already exists - * @throws DistributionSetCreationFailedMissingMandatoryModuleException - * is {@link DistributionSet} does not contain mandatory - * {@link SoftwareModule}s. - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - public List createDistributionSets(@NotNull final Iterable distributionSets) { - for (final DistributionSet ds : distributionSets) { - prepareDsSave(ds); - if (ds.getType() == null) { - ds.setType(systemManagement.getTenantMetadata().getDefaultDsType()); - } - } - return distributionSetRepository.save(distributionSets); - } - - /** - * Assigns {@link SoftwareModule} to existing {@link DistributionSet}. - * - * @param ds - * to assign and update - * @param softwareModules - * to get assigned - * @return the updated {@link DistributionSet}. - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public DistributionSet assignSoftwareModules(@NotNull final DistributionSet ds, - final Set softwareModules) { - checkDistributionSetSoftwareModulesIsAllowedToModify(ds, softwareModules); - for (final SoftwareModule softwareModule : softwareModules) { - ds.addModule(softwareModule); - } - return distributionSetRepository.save(ds); - } - - /** - * Unassigns a {@link SoftwareModule} form an existing - * {@link DistributionSet}. - * - * @param ds - * to get unassigned form - * @param softwareModule - * to get unassigned - * @return the updated {@link DistributionSet}. - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public DistributionSet unassignSoftwareModule(@NotNull final DistributionSet ds, - final SoftwareModule softwareModule) { - final Set softwareModules = new HashSet<>(); - softwareModules.add(softwareModule); - ds.removeModule(softwareModule); - checkDistributionSetSoftwareModulesIsAllowedToModify(ds, softwareModules); - return distributionSetRepository.save(ds); - } - - /** - * Updates existing {@link DistributionSetType}. However, keep in mind that - * is not possible to change the {@link DistributionSetTypeElement}s while - * the DS type is already in use. - * - * @param dsType - * to update - * @return updated {@link Entity} - * - * @throws EntityReadOnlyException - * if use tries to change the {@link DistributionSetTypeElement} - * s while the DS type is already in use. - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public DistributionSetType updateDistributionSetType(@NotNull final DistributionSetType dsType) { - checkNotNull(dsType.getId()); - - final DistributionSetType persisted = distributionSetTypeRepository.findOne(dsType.getId()); - - // throw exception if user tries to update a DS type that is already in - // use - if (!persisted.areModuleEntriesIdentical(dsType) && distributionSetRepository.countByType(persisted) > 0) { - throw new EntityReadOnlyException( - String.format("distribution set type %s set is already assigned to targets and cannot be changed", - dsType.getName())); - } - - return distributionSetTypeRepository.save(dsType); - } - - /** - * Generic predicate based query for {@link DistributionSetType}. - * - * @param spec - * of the search - * @param pageable - * parameter for paging - * - * @return the found {@link SoftwareModuleType}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findDistributionSetTypesByPredicate( - @NotNull final Specification spec, @NotNull final Pageable pageable) { - return distributionSetTypeRepository.findAll(spec, pageable); - } - - /** - * @param pageable - * parameter - * @return all {@link DistributionSetType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findDistributionSetTypesAll(@NotNull final Pageable pageable) { - return distributionSetTypeRepository.findByDeleted(pageable, false); - } - - /** - * retrieves {@link DistributionSet}s by filtering on the given parameters. - * - * @param pageable - * page parameter - * @param distributionSetFilter - * has details of filters to be applied. - * @return the page of found {@link DistributionSet} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findDistributionSetsByFilters(@NotNull final Pageable pageable, - final DistributionSetFilter distributionSetFilter) { - final List> specList = buildDistributionSetSpecifications(distributionSetFilter); - return findByCriteriaAPI(pageable, specList); - } - - /** - * - * @param distributionSetFilter - * had details of filters to be applied - * @return a single DistributionSet which is either installed or assigned to - * a specific target or {@code null}. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - private DistributionSet findDistributionSetsByFiltersAndInstalledOrAssignedTarget( - final DistributionSetFilter distributionSetFilter) { - final List> specList = buildDistributionSetSpecifications(distributionSetFilter); - if (specList == null || specList.isEmpty()) { - return null; - } - return distributionSetRepository.findOne(SpecificationsBuilder.combineWithAnd(specList)); - } - - /** - * finds all {@link DistributionSet}s. - * - * @param pageReq - * the pagination parameter - * @param deleted - * if TRUE, {@link DistributionSet}s marked as deleted are - * returned. If FALSE, on {@link DistributionSet}s with - * {@link DistributionSet#isDeleted()} == FALSE are returned. - * null if both are to be returned - * @param complete - * to true for returning only completed distribution - * sets or false for only incomplete ones nor - * null to return both.. - * @param complete - * set to if false uncomplete DS should also be - * shown. - * - * - * @return all found {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findDistributionSetsAll(@NotNull final Pageable pageReq, final Boolean deleted, - final Boolean complete) { - final List> specList = new ArrayList<>(); - - if (deleted != null) { - final Specification spec = DistributionSetSpecification.isDeleted(deleted); - specList.add(spec); - } - - if (complete != null) { - final Specification spec = DistributionSetSpecification.isCompleted(complete); - specList.add(spec); - } - - return findByCriteriaAPI(pageReq, specList); - } - - /** - * finds all {@link DistributionSet}s. - * - * @param spec - * the specification to add for the search query. - * @param pageReq - * the pagination parameter - * @param deleted - * if TRUE, {@link DistributionSet}s marked as deleted are - * returned. If FALSE, on {@link DistributionSet}s with - * {@link DistributionSet#isDeleted()} == FALSE are returned. - * null if both are to be returned - * @return all found {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findDistributionSetsAll(@NotNull final Specification spec, - @NotNull final Pageable pageReq, final Boolean deleted) { - final List> specList = new ArrayList<>(); - if (deleted != null) { - specList.add(DistributionSetSpecification.isDeleted(deleted)); - } - specList.add(spec); - return findByCriteriaAPI(pageReq, specList); - } - - /** - * method retrieves all {@link DistributionSet}s from the repo in the - * following order: - *

- * 1) {@link DistributionSet}s which have the given {@link Target} as - * {@link TargetStatus#getInstalledDistributionSet()} - *

- * 2) {@link DistributionSet}s which have the given {@link Target} as - * {@link Target#getAssignedDistributionSet()} - *

- * 3) {@link DistributionSet}s which have no connection to the given - * {@link Target} ordered by ID of the DistributionSet. - * - * @param pageable - * the page request to page the result set * - * @param distributionSetFilterBuilder - * has details of filters to be applied - * @param assignedOrInstalled - * the ID of the Target to be ordered by - * @return - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findDistributionSetsAllOrderedByLinkTarget(@NotNull final Pageable pageable, - @NotNull final DistributionSetFilterBuilder distributionSetFilterBuilder, - @NotNull final String assignedOrInstalled) { - - final DistributionSetFilter filterWithInstalledTargets = distributionSetFilterBuilder - .setInstalledTargetId(assignedOrInstalled).setAssignedTargetId(null).build(); - final DistributionSet installedDS = findDistributionSetsByFiltersAndInstalledOrAssignedTarget( - filterWithInstalledTargets); - - final DistributionSetFilter filterWithAssignedTargets = distributionSetFilterBuilder.setInstalledTargetId(null) - .setAssignedTargetId(assignedOrInstalled).build(); - final DistributionSet assignedDS = findDistributionSetsByFiltersAndInstalledOrAssignedTarget( - filterWithAssignedTargets); - - final DistributionSetFilter dsFilterWithNoTargetLinked = distributionSetFilterBuilder.setInstalledTargetId(null) - .setAssignedTargetId(null).build(); - // first fine the distribution sets filtered by the given filter - // parameters - final Page findDistributionSetsByFilters = findDistributionSetsByFilters(pageable, - dsFilterWithNoTargetLinked); - - final List resultSet = new LinkedList<>(findDistributionSetsByFilters.getContent()); - int orderIndex = 0; - if (installedDS != null) { - final boolean remove = resultSet.remove(installedDS); - if (!remove) { - resultSet.remove(resultSet.size() - 1); - } - resultSet.add(orderIndex, installedDS); - orderIndex++; - } - if (assignedDS != null && !assignedDS.equals(installedDS)) { - final boolean remove = resultSet.remove(assignedDS); - if (!remove) { - resultSet.remove(resultSet.size() - 1); - } - resultSet.add(orderIndex, assignedDS); - } - - return new PageImpl<>(resultSet, pageable, findDistributionSetsByFilters.getTotalElements()); - } - - /** - * Find distribution set by name and version. - * - * @param distributionName - * name of {@link DistributionSet}; case insensitive - * @param version - * version of {@link DistributionSet} - * @return the page with the found {@link DistributionSet} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public DistributionSet findDistributionSetByNameAndVersion(@NotEmpty final String distributionName, - @NotEmpty final String version) { - final Specification spec = DistributionSetSpecification - .equalsNameAndVersionIgnoreCase(distributionName, version); - return distributionSetRepository.findOne(spec); - - } - - /** - * Retrieves {@link DistributionSet} List for overview purposes (no - * {@link SoftwareModule}s and {@link DistributionSetTag}s). - * - * Please use {@link #findDistributionSetListWithDetails(Iterable)} if - * details are required. - * - * @param dist - * List of {@link DistributionSet} IDs to be found - * @return the found {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Iterable findDistributionSetList(@NotEmpty final Collection dist) { - return distributionSetRepository.findAll(dist); - } - - /** - * Count all {@link DistributionSet}s in the repository that are not marked - * as deleted. - * - * @return number of {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Long countDistributionSetsAll() { - - final List> specList = new ArrayList<>(); - - final Specification spec = DistributionSetSpecification.isDeleted(Boolean.FALSE); - specList.add(spec); - - return distributionSetRepository.count(SpecificationsBuilder.combineWithAnd(specList)); - } - - /** - * @return number of {@link DistributionSetType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Long countDistributionSetTypesAll() { - return distributionSetTypeRepository.countByDeleted(false); - } - - /** - * @param name - * as {@link DistributionSetType#getName()} - * @return {@link DistributionSetType} if found or null if not - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public DistributionSetType findDistributionSetTypeByName(@NotNull final String name) { - return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byName(name)); - } - - /** - * @param id - * as {@link DistributionSetType#getId()} - * @return {@link DistributionSetType} if found or null if not - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public DistributionSetType findDistributionSetTypeById(@NotNull final Long id) { - return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byId(id)); - } - - /** - * @param key - * as {@link DistributionSetType#getKey()} - * @return {@link DistributionSetType} if found or null if not - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public DistributionSetType findDistributionSetTypeByKey(@NotNull final String key) { - return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byKey(key)); - } - - /** - * Creates new {@link DistributionSetType}. - * - * @param type - * to create - * @return created {@link Entity} - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - public DistributionSetType createDistributionSetType(@NotNull final DistributionSetType type) { - if (type.getId() != null) { - throw new EntityAlreadyExistsException("Given type contains an Id!"); - } - - return distributionSetTypeRepository.save(type); - } - - /** - * Deletes or markes as delete in case the type is in use. - * - * @param type - * to delete - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - public void deleteDistributionSetType(@NotNull final DistributionSetType type) { - - if (distributionSetRepository.countByType(type) > 0) { - final DistributionSetType toDelete = entityManager.merge(type); - toDelete.setDeleted(true); - distributionSetTypeRepository.save(toDelete); - } else { - distributionSetTypeRepository.delete(type.getId()); - } - } - - /** - * creates or updates a single distribution set meta data entry. - * - * @param metadata - * the meta data entry to create or update - * @return the updated or created distribution set meta data entry - * @throws EntityAlreadyExistsException - * in case the meta data entry already exists for the specific - * key - */ - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public DistributionSetMetadata createDistributionSetMetadata(@NotNull final DistributionSetMetadata metadata) { - if (distributionSetMetadataRepository.exists(metadata.getId())) { - throwMetadataKeyAlreadyExists(metadata.getId().getKey()); - } - // merge base distribution set so optLockRevision gets updated and audit - // log written because - // modifying metadata is modifying the base distribution set itself for - // auditing purposes. - entityManager.merge(metadata.getDistributionSet()).setLastModifiedAt(0L); - return distributionSetMetadataRepository.save(metadata); - } - - /** - * creates a list of distribution set meta data entries. - * - * @param metadata - * the meta data entries to create or update - * @return the updated or created distribution set meta data entries - * @throws EntityAlreadyExistsException - * in case one of the meta data entry already exists for the - * specific key - */ - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public List createDistributionSetMetadata( - @NotEmpty final Collection metadata) { - for (final DistributionSetMetadata distributionSetMetadata : metadata) { - checkAndThrowAlreadyIfDistributionSetMetadataExists(distributionSetMetadata.getId()); - } - metadata.forEach(m -> entityManager.merge(m.getDistributionSet()).setLastModifiedAt(-1L)); - return (List) distributionSetMetadataRepository.save(metadata); - } - - /** - * updates a distribution set meta data value if corresponding entry exists. - * - * @param metadata - * the meta data entry to be updated - * @return the updated meta data entry - * @throws EntityNotFoundException - * in case the meta data entry does not exists and cannot be - * updated - */ - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public DistributionSetMetadata updateDistributionSetMetadata(@NotNull final DistributionSetMetadata metadata) { - // check if exists otherwise throw entity not found exception - findOne(metadata.getId()); - // touch it to update the lock revision because we are modifying the - // DS indirectly - entityManager.merge(metadata.getDistributionSet()).setLastModifiedAt(0L); - return distributionSetMetadataRepository.save(metadata); - } - - /** - * deletes a distribution set meta data entry. - * - * @param id - * the ID of the distribution set meta data to delete - */ - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public void deleteDistributionSetMetadata(@NotNull final DsMetadataCompositeKey id) { - distributionSetMetadataRepository.delete(id); - } - - /** - * finds all meta data by the given distribution set id. - * - * @param distributionSetId - * the distribution set id to retrieve the meta data from - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given distribution - * set id - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findDistributionSetMetadataByDistributionSetId( - @NotNull final Long distributionSetId, @NotNull final Pageable pageable) { - - return distributionSetMetadataRepository.findAll( - (Specification) (root, query, cb) -> cb.equal( - root.get(DistributionSetMetadata_.distributionSet).get(DistributionSet_.id), distributionSetId), - pageable); - - } - - /** - * finds all meta data by the given distribution set id. - * - * @param distributionSetId - * the distribution set id to retrieve the meta data from - * @param spec - * the specification to filter the result - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given distribution - * set id - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findDistributionSetMetadataByDistributionSetId( - @NotNull final Long distributionSetId, @NotNull final Specification spec, - @NotNull final Pageable pageable) { - return distributionSetMetadataRepository - .findAll( - (Specification) (root, query, - cb) -> cb.and( - cb.equal(root.get(DistributionSetMetadata_.distributionSet) - .get(DistributionSet_.id), distributionSetId), - spec.toPredicate(root, query, cb)), - pageable); - } - - /** - * finds a single distribution set meta data by its id. - * - * @param id - * the id of the distribution set meta data containing the meta - * data key and the ID of the distribution set - * @return the found DistributionSetMetadata or {@code null} if not exits - * @throws EntityNotFoundException - * in case the meta data does not exists for the given key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public DistributionSetMetadata findOne(@NotNull final DsMetadataCompositeKey id) { - final DistributionSetMetadata findOne = distributionSetMetadataRepository.findOne(id); - if (findOne == null) { - throw new EntityNotFoundException("Metadata with key '" + id.getKey() + "' does not exist"); - } - return findOne; - } - - /** - * retrieves the distribution set for a given action. - * - * @param action - * the action associated with the distribution set - * @return the distribution set which is associated with the action - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public DistributionSet findDistributionSetByAction(@NotNull final Action action) { - return distributionSetRepository.findByAction(action); - } - - /** - * Creates multiple {@link DistributionSetType}s. - * - * @param types - * to create - * @return created {@link Entity} - */ - @Modifying - @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()); - } - - /** - * Checking Distribution Set is already using while assign Software module. - * - * @param distributionSet - * @param softwareModules - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public void checkDistributionSetAlreadyUse(final DistributionSet distributionSet) { - checkDistributionSetSoftwareModulesIsAllowedToModify(distributionSet); - } - - private List> buildDistributionSetSpecifications( - final DistributionSetFilter distributionSetFilter) { - final List> specList = new ArrayList<>(); - - Specification spec; - - if (null != distributionSetFilter.getIsComplete()) { - spec = DistributionSetSpecification.isCompleted(distributionSetFilter.getIsComplete()); - specList.add(spec); - } - - if (null != distributionSetFilter.getIsDeleted()) { - spec = DistributionSetSpecification.isDeleted(distributionSetFilter.getIsDeleted()); - specList.add(spec); - } - - if (distributionSetFilter.getType() != null) { - spec = DistributionSetSpecification.byType(distributionSetFilter.getType()); - specList.add(spec); - } - - if (!Strings.isNullOrEmpty(distributionSetFilter.getSearchText())) { - spec = DistributionSetSpecification.likeNameOrDescriptionOrVersion(distributionSetFilter.getSearchText()); - specList.add(spec); - } - - if (isDSWithNoTagSelected(distributionSetFilter) || isTagsSelected(distributionSetFilter)) { - spec = DistributionSetSpecification.hasTags(distributionSetFilter.getTagNames(), - distributionSetFilter.getSelectDSWithNoTag()); - specList.add(spec); - } - if (distributionSetFilter.getInstalledTargetId() != null) { - spec = DistributionSetSpecification.installedTarget(distributionSetFilter.getInstalledTargetId()); - specList.add(spec); - } - if (distributionSetFilter.getAssignedTargetId() != null) { - spec = DistributionSetSpecification.assignedTarget(distributionSetFilter.getAssignedTargetId()); - specList.add(spec); - } - return specList; - } - - private void checkDistributionSetSoftwareModulesIsAllowedToModify(final DistributionSet distributionSet, - final Set softwareModules) { - if (!new HashSet(distributionSet.getModules()).equals(softwareModules) - && actionRepository.countByDistributionSet(distributionSet) > 0) { - throw new EntityLockedException( - String.format("distribution set %s:%s is already assigned to targets and cannot be changed", - distributionSet.getName(), distributionSet.getVersion())); - } - } - - private void checkDistributionSetSoftwareModulesIsAllowedToModify(final DistributionSet distributionSet) { - if (actionRepository.countByDistributionSet(distributionSet) > 0) { - throw new EntityLockedException( - String.format("distribution set %s:%s is already assigned to targets and cannot be changed", - distributionSet.getName(), distributionSet.getVersion())); - } - } - - private static Boolean isDSWithNoTagSelected(final DistributionSetFilter distributionSetFilter) { - if (distributionSetFilter.getSelectDSWithNoTag() != null && distributionSetFilter.getSelectDSWithNoTag()) { - return true; - } - return false; - } - - private static Boolean isTagsSelected(final DistributionSetFilter distributionSetFilter) { - if (distributionSetFilter.getTagNames() != null && !distributionSetFilter.getTagNames().isEmpty()) { - return true; - } - return false; - } - - /** - * executes findAll with the given {@link DistributionSet} - * {@link Specification}s. - * - * @param pageable - * paging parameter - * @param specList - * list of @link {@link Specification} - * @return the page with the found {@link DistributionSet} - */ - private Page findByCriteriaAPI(@NotNull final Pageable pageable, - final List> specList) { - - if (specList == null || specList.isEmpty()) { - return distributionSetRepository.findAll(pageable); - } - - return distributionSetRepository.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable); - } - - private void checkAndThrowAlreadyIfDistributionSetMetadataExists(final DsMetadataCompositeKey metadataId) { - if (distributionSetMetadataRepository.exists(metadataId)) { - throw new EntityAlreadyExistsException( - "Metadata entry with key '" + metadataId.getKey() + "' already exists"); - } - } - - private static void throwMetadataKeyAlreadyExists(final String metadataKey) { - throw new EntityAlreadyExistsException("Metadata entry with key '" + metadataKey + "' already exists"); - } - - /** - * Assign a {@link DistributionSetTag} assignment to given - * {@link DistributionSet}s. - * - * @param dsIds - * to assign for - * @param tag - * to assign - * @return list of assigned ds - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - public List assignTag(@NotEmpty final Collection dsIds, - @NotNull final DistributionSetTag tag) { - final List allDs = findDistributionSetListWithDetails(dsIds); - - allDs.forEach(ds -> ds.getTags().add(tag)); - final List save = distributionSetRepository.save(allDs); - - afterCommit.afterCommit(() -> { - - final DistributionSetTagAssignmentResult result = new DistributionSetTagAssignmentResult(0, save.size(), 0, - save, Collections.emptyList(), tag); - eventBus.post(new DistributionSetTagAssigmentResultEvent(result)); - }); - - return save; - } - - /** - * Unassign all {@link DistributionSet} from a given - * {@link DistributionSetTag} . - * - * @param tag - * to unassign all ds - * @return list of unassigned ds - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - public List unAssignAllDistributionSetsByTag(@NotNull final DistributionSetTag tag) { - return unAssignTag(tag.getAssignedToDistributionSet(), tag); - } - - /** - * Unassign a {@link DistributionSetTag} assignment to given - * {@link DistributionSet}. - * - * @param dsId - * to unassign for - * @param distributionSetTag - * to unassign - * @return the unassigned ds or if no ds is unassigned - */ - @Modifying - @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)); - final List unAssignTag = unAssignTag(allDs, distributionSetTag); - return unAssignTag.isEmpty() ? null : unAssignTag.get(0); - } - - private List unAssignTag(final Collection distributionSets, - final DistributionSetTag tag) { - distributionSets.forEach(ds -> ds.getTags().remove(tag)); - return distributionSetRepository.save(distributionSets); - } -} 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 deleted file mode 100644 index d719667ed..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java +++ /dev/null @@ -1,933 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.persistence.Entity; -import javax.persistence.EntityManager; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.ListJoin; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.model.CustomSoftwareModule; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSet_; -import org.eclipse.hawkbit.repository.model.LocalArtifact; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata_; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.model.SoftwareModule_; -import org.eclipse.hawkbit.repository.model.SwMetadataCompositeKey; -import org.eclipse.hawkbit.repository.specifications.SoftwareModuleSpecification; -import org.eclipse.hawkbit.repository.specifications.SpecificationsBuilder; -import org.hibernate.validator.constraints.NotEmpty; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.AuditorAware; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.data.domain.SliceImpl; -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.base.Strings; -import com.google.common.collect.Sets; - -/** - * Business facade for managing {@link SoftwareModule}s. - * - */ -@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -@Validated -@Service -public class SoftwareManagement { - - @Autowired - private EntityManager entityManager; - - @Autowired - private DistributionSetRepository distributionSetRepository; - - @Autowired - private DistributionSetTypeRepository distributionSetTypeRepository; - - @Autowired - private SoftwareModuleRepository softwareModuleRepository; - - @Autowired - private SoftwareModuleMetadataRepository softwareModuleMetadataRepository; - - @Autowired - private SoftwareModuleTypeRepository softwareModuleTypeRepository; - - @Autowired - private NoCountPagingRepository criteriaNoCountDao; - - @Autowired - private AuditorAware auditorProvider; - - @Autowired - private ArtifactManagement artifactManagement; - - /** - * Updates existing {@link SoftwareModule}. Update-able values are - * {@link SoftwareModule#getDescription()} - * {@link SoftwareModule#getVendor()}. - * - * @param sm - * to update - * - * @return the saved {@link Entity}. - * - * @throws NullPointerException - * of {@link SoftwareModule#getId()} is null - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public SoftwareModule updateSoftwareModule(@NotNull final SoftwareModule sm) { - checkNotNull(sm.getId()); - - final SoftwareModule module = softwareModuleRepository.findOne(sm.getId()); - - boolean updated = false; - if (null == sm.getDescription() || !sm.getDescription().equals(module.getDescription())) { - module.setDescription(sm.getDescription()); - updated = true; - } - if (null == sm.getVendor() || !sm.getVendor().equals(module.getVendor())) { - module.setVendor(sm.getVendor()); - updated = true; - } - - return updated ? softwareModuleRepository.save(module) : module; - } - - /** - * Updates existing {@link SoftwareModuleType}. Update-able value is - * {@link SoftwareModuleType#getDescription()} and - * {@link SoftwareModuleType#getColour()}. - * - * @param sm - * to update - * @return updated {@link Entity} - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public SoftwareModuleType updateSoftwareModuleType(@NotNull final SoftwareModuleType sm) { - checkNotNull(sm.getId()); - - final SoftwareModuleType type = softwareModuleTypeRepository.findOne(sm.getId()); - - boolean updated = false; - if (sm.getDescription() != null && !sm.getDescription().equals(type.getDescription())) { - type.setDescription(sm.getDescription()); - updated = true; - } - if (sm.getColour() != null && !sm.getColour().equals(type.getColour())) { - type.setColour(sm.getColour()); - updated = true; - } - return updated ? softwareModuleTypeRepository.save(type) : type; - } - - /** - * - * @param swModule - * SoftwareModule to create - * @return SoftwareModule - * @throws EntityAlreadyExistsException - * if a given entity already exists - */ - @Modifying - @Transactional - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - public SoftwareModule createSoftwareModule(@NotNull final SoftwareModule swModule) { - if (null != swModule.getId()) { - throw new EntityAlreadyExistsException(); - } - return softwareModuleRepository.save(swModule); - } - - /** - * Create {@link SoftwareModule}s in the repository. - * - * @param swModules - * {@link SoftwareModule}s to create - * @return SoftwareModule - * @throws EntityAlreadyExistsException - * if a given entity already exists - */ - @Modifying - @Transactional - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - public List createSoftwareModule(@NotNull final Iterable swModules) { - swModules.forEach(swModule -> { - if (null != swModule.getId()) { - throw new EntityAlreadyExistsException(); - } - }); - - return softwareModuleRepository.save(swModules); - - } - - /** - * retrieves the {@link SoftwareModule}s by their {@link SoftwareModuleType} - * . - * - * @param pageable - * page parameters - * @param type - * to be filtered on - * @return the found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Slice findSoftwareModulesByType(@NotNull final Pageable pageable, - @NotNull final SoftwareModuleType type) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.equalType(type); - specList.add(spec); - - spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - return findSwModuleByCriteriaAPI(pageable, specList); - } - - /** - * Counts {@link SoftwareModule}s with given {@link SoftwareModuleType}. - * - * @param type - * to count - * @return number of found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Long countSoftwareModulesByType(@NotNull final SoftwareModuleType type) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.equalType(type); - specList.add(spec); - - spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - return countSwModuleByCriteriaAPI(specList); - } - - /** - * Finds {@link SoftwareModule} by given id. - * - * @param id - * to search for - * @return the found {@link SoftwareModule}s or null if not - * found. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) - public SoftwareModule findSoftwareModuleById(@NotNull final Long id) { - return artifactManagement.findSoftwareModuleById(id); - } - - /** - * retrieves {@link SoftwareModule} by their name AND version AND type.. - * - * @param name - * of the {@link SoftwareModule} - * @param version - * of the {@link SoftwareModule} - * @param type - * of the {@link SoftwareModule} - * @return the found {@link SoftwareModule} or null - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public SoftwareModule findSoftwareModuleByNameAndVersion(@NotEmpty final String name, - @NotEmpty final String version, @NotNull final SoftwareModuleType type) { - - return softwareModuleRepository.findOneByNameAndVersionAndType(name, version, type); - } - - /** - * Deletes the given {@link SoftwareModule} {@link Entity}. - * - * @param bsm - * is the {@link SoftwareModule} to be deleted - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - public void deleteSoftwareModule(@NotNull final SoftwareModule bsm) { - - deleteSoftwareModules(Sets.newHashSet(bsm.getId())); - } - - private boolean isUnassigned(final SoftwareModule bsmMerged) { - return distributionSetRepository.findByModules(bsmMerged).isEmpty(); - } - - private Slice findSwModuleByCriteriaAPI(@NotNull final Pageable pageable, - @NotEmpty final List> specList) { - return criteriaNoCountDao.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable, - SoftwareModule.class); - } - - private Long countSwModuleByCriteriaAPI(@NotEmpty final List> specList) { - return softwareModuleRepository.count(SpecificationsBuilder.combineWithAnd(specList)); - } - - private void deleteGridFsArtifacts(final SoftwareModule swModule) { - for (final LocalArtifact localArtifact : swModule.getLocalArtifacts()) { - artifactManagement.deleteGridFsArtifact(localArtifact); - } - } - - /** - * Deletes {@link SoftwareModule}s which is any if the given ids. - * - * @param ids - * of the Software Modules to be deleted - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - public void deleteSoftwareModules(@NotNull final Iterable ids) { - final List swModulesToDelete = softwareModuleRepository.findByIdIn(ids); - final Set assignedModuleIds = new HashSet<>(); - swModulesToDelete.forEach(swModule -> { - - // delete binary data of artifacts - deleteGridFsArtifacts(swModule); - - if (isUnassigned(swModule)) { - - softwareModuleRepository.delete(swModule); - - } else { - - assignedModuleIds.add(swModule.getId()); - } - }); - - if (!assignedModuleIds.isEmpty()) { - String currentUser = null; - if (auditorProvider != null) { - currentUser = auditorProvider.getCurrentAuditor(); - } - softwareModuleRepository.deleteSoftwareModule(System.currentTimeMillis(), currentUser, - assignedModuleIds.toArray(new Long[0])); - } - } - - /** - * Retrieves all software modules. Deleted ones are filtered. - * - * @param pageable - * pagination parameter - * @return the found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Slice findSoftwareModulesAll(@NotNull final Pageable pageable) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - spec = (root, query, cb) -> { - if (!query.getResultType().isAssignableFrom(Long.class)) { - root.fetch(SoftwareModule_.type); - } - return cb.conjunction(); - }; - - specList.add(spec); - - return findSwModuleByCriteriaAPI(pageable, specList); - } - - /** - * Count all {@link SoftwareModule}s in the repository that are not marked - * as deleted. - * - * @return number of {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Long countSoftwareModulesAll() { - - final List> specList = new ArrayList<>(); - - final Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - return countSwModuleByCriteriaAPI(specList); - } - - /** - * Retrieves software module including details ( - * {@link SoftwareModule#getArtifacts()}). - * - * @param id - * parameter - * @param isDeleted - * parameter - * @return the found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public SoftwareModule findSoftwareModuleWithDetails(@NotNull final Long id) { - return artifactManagement.findSoftwareModuleWithDetails(id); - } - - /** - * Retrieves all {@link SoftwareModule}s with a given specification. - * - * @param spec - * the specification to filter the software modules - * @param pageable - * pagination parameter - * @return the found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findSoftwareModulesByPredicate(@NotNull final Specification spec, - @NotNull final Pageable pageable) { - return softwareModuleRepository.findAll(spec, pageable); - } - - /** - * Retrieves all {@link SoftwareModuleType}s with a given specification. - * - * @param spec - * the specification to filter the software modules types - * @param pageable - * pagination parameter - * @return the found {@link SoftwareModuleType}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findSoftwareModuleTypesByPredicate( - @NotNull final Specification spec, @NotNull final Pageable pageable) { - return softwareModuleTypeRepository.findAll(spec, pageable); - } - - /** - * Retrieves all software modules with a given list of ids - * {@link SoftwareModule#getId()}. - * - * @param ids - * to search for - * @return {@link List} of found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public List findSoftwareModulesById(@NotEmpty final List ids) { - return softwareModuleRepository.findByIdIn(ids); - } - - /** - * Filter {@link SoftwareModule}s with given - * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} - * and {@link SoftwareModule#getType()} that are not marked as deleted. - * - * @param pageable - * page parameter - * @param searchText - * to be filtered as "like" on {@link SoftwareModule#getName()} - * @param type - * to be filtered as "like" on {@link SoftwareModule#getType()} - * @return the page of found {@link SoftwareModule} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Slice findSoftwareModuleByFilters(@NotNull final Pageable pageable, final String searchText, - final SoftwareModuleType type) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - if (!Strings.isNullOrEmpty(searchText)) { - spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); - specList.add(spec); - } - - if (null != type) { - spec = SoftwareModuleSpecification.equalType(type); - specList.add(spec); - } - - spec = (root, query, cb) -> { - if (!query.getResultType().isAssignableFrom(Long.class)) { - root.fetch(SoftwareModule_.type); - } - return cb.conjunction(); - }; - - specList.add(spec); - - return findSwModuleByCriteriaAPI(pageable, specList); - } - - /** - * Filter {@link SoftwareModule}s with given - * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} - * search text and {@link SoftwareModule#getType()} that are not marked as - * deleted and sort them by means of given distribution set related modules - * on top of the list. - * - * After that the modules are sorted by {@link SoftwareModule#getName()} and - * {@link SoftwareModule#getVersion()} in ascending order. - * - * @param pageable - * page parameter - * @param orderByDistributionId - * the ID of distribution set to be ordered on top - * @param searchText - * filtered as "like" on {@link SoftwareModule#getName()} - * @param type - * filtered as "equal" on {@link SoftwareModule#getType()} - * @return the page of found {@link SoftwareModule} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Slice findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc( - @NotNull final Pageable pageable, @NotNull final Long orderByDistributionId, final String searchText, - final SoftwareModuleType type) { - - final List resultList = new ArrayList<>(); - final int pageSize = pageable.getPageSize(); - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - - // get the assigned software modules - final CriteriaQuery assignedQuery = cb.createQuery(SoftwareModule.class); - final Root assignedRoot = assignedQuery.from(SoftwareModule.class); - assignedQuery.distinct(true); - final ListJoin assignedDsJoin = assignedRoot.join(SoftwareModule_.assignedTo); - // build the specifications and then to predicates necessary by the - // given filters - final Predicate[] specPredicate = specificationsToPredicate(buildSpecificationList(searchText, type), - assignedRoot, assignedQuery, cb, - cb.equal(assignedDsJoin.get(DistributionSet_.id), orderByDistributionId)); - // if we have some predicates then add it to the where clause of the - // multi select - assignedQuery.where(specPredicate); - assignedQuery.orderBy(cb.asc(assignedRoot.get(SoftwareModule_.name)), - cb.asc(assignedRoot.get(SoftwareModule_.version))); - // don't page the assigned query on database, we need all assigned - // software modules to filter - // them out in the unassigned query - final List assignedSoftwareModules = entityManager.createQuery(assignedQuery).getResultList(); - // map result - if (pageable.getOffset() < assignedSoftwareModules.size()) { - assignedSoftwareModules - .subList(pageable.getOffset(), Math.min(assignedSoftwareModules.size(), pageable.getPageSize())) - .forEach(sw -> resultList.add(new CustomSoftwareModule(sw, true))); - } - - if (assignedSoftwareModules.size() >= pageSize) { - return new SliceImpl<>(resultList); - } - - // get the unassigned software modules - final CriteriaQuery unassignedQuery = cb.createQuery(SoftwareModule.class); - unassignedQuery.distinct(true); - final Root unassignedRoot = unassignedQuery.from(SoftwareModule.class); - - Predicate[] unassignedSpec; - if (!assignedSoftwareModules.isEmpty()) { - unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, - unassignedQuery, cb, cb.not(unassignedRoot.get(SoftwareModule_.id) - .in(assignedSoftwareModules.stream().map(sw -> sw.getId()).collect(Collectors.toList())))); - } else { - unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, - unassignedQuery, cb); - } - - unassignedQuery.where(unassignedSpec); - unassignedQuery.orderBy(cb.asc(unassignedRoot.get(SoftwareModule_.name)), - cb.asc(unassignedRoot.get(SoftwareModule_.version))); - final List unassignedSoftwareModules = entityManager.createQuery(unassignedQuery) - .setFirstResult(Math.max(0, pageable.getOffset() - assignedSoftwareModules.size())) - .setMaxResults(pageSize).getResultList(); - // map result - unassignedSoftwareModules.forEach(sw -> resultList.add(new CustomSoftwareModule(sw, false))); - - return new SliceImpl<>(resultList); - } - - private static List> buildSpecificationList(final String searchText, - final SoftwareModuleType type) { - final List> specList = new ArrayList<>(); - if (!Strings.isNullOrEmpty(searchText)) { - specList.add(SoftwareModuleSpecification.likeNameOrVersion(searchText)); - } - if (type != null) { - specList.add(SoftwareModuleSpecification.equalType(type)); - } - specList.add(SoftwareModuleSpecification.isDeletedFalse()); - return specList; - } - - /** - * @param specifications - */ - private Predicate[] specificationsToPredicate(final List> specifications, - final Root root, final CriteriaQuery query, final CriteriaBuilder cb, - final Predicate... additionalPredicates) { - final List predicates = new ArrayList<>(); - specifications.forEach(spec -> predicates.add(spec.toPredicate(root, query, cb))); - for (final Predicate predicate : additionalPredicates) { - predicates.add(predicate); - } - return predicates.toArray(new Predicate[predicates.size()]); - } - - /** - * Counts {@link SoftwareModule}s with given - * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} - * and {@link SoftwareModule#getType()} that are not marked as deleted. - * - * @param searchText - * to search for in name and version - * @param type - * to filter the result - * @return number of found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Long countSoftwareModuleByFilters(final String searchText, final SoftwareModuleType type) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - if (!Strings.isNullOrEmpty(searchText)) { - spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); - specList.add(spec); - } - - if (null != type) { - spec = SoftwareModuleSpecification.equalType(type); - specList.add(spec); - } - - return countSwModuleByCriteriaAPI(specList); - } - - /** - * @param pageable - * parameter - * @return all {@link SoftwareModuleType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findSoftwareModuleTypesAll(@NotNull final Pageable pageable) { - return softwareModuleTypeRepository.findByDeleted(pageable, false); - } - - /** - * @return number of {@link SoftwareModuleType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Long countSoftwareModuleTypesAll() { - return softwareModuleTypeRepository.countByDeleted(false); - } - - /** - * - * @param key - * to search for - * @return {@link SoftwareModuleType} in the repository with given - * {@link SoftwareModuleType#getKey()} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public SoftwareModuleType findSoftwareModuleTypeByKey(@NotNull final String key) { - return softwareModuleTypeRepository.findByKey(key); - } - - /** - * - * @param id - * to search for - * @return {@link SoftwareModuleType} in the repository with given - * {@link SoftwareModuleType#getId()} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public SoftwareModuleType findSoftwareModuleTypeById(@NotNull final Long id) { - return softwareModuleTypeRepository.findOne(id); - } - - /** - * - * @param name - * to search for - * @return all {@link SoftwareModuleType}s in the repository with given - * {@link SoftwareModuleType#getName()} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public SoftwareModuleType findSoftwareModuleTypeByName(@NotNull final String name) { - return softwareModuleTypeRepository.findByName(name); - } - - /** - * Creates new {@link SoftwareModuleType}. - * - * @param type - * to create - * @return created {@link Entity} - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - public SoftwareModuleType createSoftwareModuleType(@NotNull final SoftwareModuleType type) { - if (type.getId() != null) { - throw new EntityAlreadyExistsException("Given type contains an Id!"); - } - - return softwareModuleTypeRepository.save(type); - } - - /** - * Creates multiple {@link SoftwareModuleType}s. - * - * @param types - * to create - * @return created {@link Entity} - */ - @Modifying - @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()); - } - - /** - * Deletes or markes as delete in case the type is in use. - * - * @param type - * to delete - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - public void deleteSoftwareModuleType(@NotNull final SoftwareModuleType type) { - - if (softwareModuleRepository.countByType(type) > 0 - || distributionSetTypeRepository.countByElementsSmType(type) > 0) { - final SoftwareModuleType toDelete = entityManager.merge(type); - toDelete.setDeleted(true); - softwareModuleTypeRepository.save(toDelete); - } else { - softwareModuleTypeRepository.delete(type.getId()); - } - } - - /** - * @param pageable - * the page request to page the result set - * @param set - * to search for - * @return all {@link SoftwareModule}s that are assigned to given - * {@link DistributionSet}. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findSoftwareModuleByAssignedTo(@NotNull final Pageable pageable, - @NotNull final DistributionSet set) { - return softwareModuleRepository.findByAssignedTo(pageable, set); - } - - /** - * @param pageable - * the page request to page the result set - * @param set - * to search for - * @param type - * to filter - * @return all {@link SoftwareModule}s that are assigned to given - * {@link DistributionSet} filtered by {@link SoftwareModuleType}. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findSoftwareModuleByAssignedToAndType(@NotNull final Pageable pageable, - @NotNull final DistributionSet set, @NotNull final SoftwareModuleType type) { - return softwareModuleRepository.findByAssignedToAndType(pageable, set, type); - } - - /** - * creates or updates a single software module meta data entry. - * - * @param metadata - * the meta data entry to create or update - * @return the updated or created software module meta data entry - * @throws EntityAlreadyExistsException - * in case the meta data entry already exists for the specific - * key - */ - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public SoftwareModuleMetadata createSoftwareModuleMetadata(@NotNull final SoftwareModuleMetadata metadata) { - if (softwareModuleMetadataRepository.exists(metadata.getId())) { - throwMetadataKeyAlreadyExists(metadata.getId().getKey()); - } - // merge base software module so optLockRevision gets updated and audit - // log written because - // modifying metadata is modifying the base software module itself for - // auditing purposes. - entityManager.merge(metadata.getSoftwareModule()).setLastModifiedAt(-1L); - return softwareModuleMetadataRepository.save(metadata); - } - - /** - * creates a list of software module meta data entries. - * - * @param metadata - * the meta data entries to create or update - * @return the updated or created software module meta data entries - * @throws EntityAlreadyExistsException - * in case one of the meta data entry already exists for the - * specific key - */ - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public List createSoftwareModuleMetadata( - @NotEmpty final Collection metadata) { - for (final SoftwareModuleMetadata softwareModuleMetadata : metadata) { - checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(softwareModuleMetadata.getId()); - } - metadata.forEach(m -> entityManager.merge(m.getSoftwareModule()).setLastModifiedAt(-1L)); - return softwareModuleMetadataRepository.save(metadata); - } - - /** - * updates a distribution set meta data value if corresponding entry exists. - * - * @param metadata - * the meta data entry to be updated - * @return the updated meta data entry - * @throws EntityNotFoundException - * in case the meta data entry does not exists and cannot be - * updated - */ - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public SoftwareModuleMetadata updateSoftwareModuleMetadata(@NotNull final SoftwareModuleMetadata metadata) { - // check if exists otherwise throw entity not found exception - findSoftwareModuleMetadata(metadata.getId()); - // touch it to update the lock revision because we are modifying the - // software module - // indirectly - entityManager.merge(metadata.getSoftwareModule()).setLastModifiedAt(-1L); - return softwareModuleMetadataRepository.save(metadata); - } - - /** - * deletes a software module meta data entry. - * - * @param id - * the ID of the software module meta data to delete - */ - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public void deleteSoftwareModuleMetadata(@NotNull final SwMetadataCompositeKey id) { - softwareModuleMetadataRepository.delete(id); - } - - /** - * finds all meta data by the given software module id. - * - * @param swId - * the software module id to retrieve the meta data from - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given software - * module id - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findSoftwareModuleMetadataBySoftwareModuleId(@NotNull final Long swId, - @NotNull final Pageable pageable) { - return softwareModuleMetadataRepository.findBySoftwareModuleId(swId, pageable); - } - - /** - * finds all meta data by the given software module id. - * - * @param softwareModuleId - * the software module id to retrieve the meta data from - * @param spec - * the specification to filter the result - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given software - * module id - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId, - @NotNull final Specification spec, @NotNull final Pageable pageable) { - return softwareModuleMetadataRepository - .findAll( - (Specification) (root, query, - cb) -> cb.and( - cb.equal(root.get(SoftwareModuleMetadata_.softwareModule) - .get(SoftwareModule_.id), softwareModuleId), - spec.toPredicate(root, query, cb)), - pageable); - } - - /** - * finds a single software module meta data by its id. - * - * @param id - * the id of the software module meta data containing the meta - * data key and the ID of the software module - * @return the found SoftwareModuleMetadata or {@code null} if not exits - * @throws EntityNotFoundException - * in case the meta data does not exists for the given key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public SoftwareModuleMetadata findSoftwareModuleMetadata(@NotNull final SwMetadataCompositeKey id) { - final SoftwareModuleMetadata findOne = softwareModuleMetadataRepository.findOne(id); - if (findOne == null) { - throw new EntityNotFoundException("Metadata with key '" + id.getKey() + "' does not exist"); - } - return findOne; - } - - private void checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(final SwMetadataCompositeKey metadataId) { - if (softwareModuleMetadataRepository.exists(metadataId)) { - throw new EntityAlreadyExistsException( - "Metadata entry with key '" + metadataId.getKey() + "' already exists"); - } - } - - 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/TagManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TagManagement.java deleted file mode 100644 index 8db9773e6..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TagManagement.java +++ /dev/null @@ -1,423 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.LinkedList; -import java.util.List; - -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.eventbus.event.DistributionSetTagCreatedBulkEvent; -import org.eclipse.hawkbit.eventbus.event.DistributionSetTagDeletedEvent; -import org.eclipse.hawkbit.eventbus.event.DistributionSetTagUpdateEvent; -import org.eclipse.hawkbit.eventbus.event.TargetTagCreatedBulkEvent; -import org.eclipse.hawkbit.eventbus.event.TargetTagDeletedEvent; -import org.eclipse.hawkbit.eventbus.event.TargetTagUpdateEvent; -import org.eclipse.hawkbit.executor.AfterTransactionCommitExecutor; -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetTag; -import org.eclipse.hawkbit.repository.model.Tag; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetTag; -import org.eclipse.hawkbit.tenancy.TenantAware; -import org.hibernate.validator.constraints.NotEmpty; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -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; - -/** - * Management service class for {@link Tag}s. - * - */ -@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -@Validated -@Service -public class TagManagement { - - @Autowired - private TargetTagRepository targetTagRepository; - - @Autowired - private TargetRepository targetRepository; - - @Autowired - private DistributionSetTagRepository distributionSetTagRepository; - - @Autowired - private DistributionSetRepository distributionSetRepository; - - @Autowired - private EventBus eventBus; - - @Autowired - private TenantAware tenantAware; - - @Autowired - private AfterTransactionCommitExecutor afterCommit; - - /** - * Find {@link TargetTag} based on given Name. - * - * @param name - * to look for. - * @return {@link TargetTag} or null if it does not exist - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public TargetTag findTargetTag(@NotEmpty final String name) { - return targetTagRepository.findByNameEquals(name); - } - - /** - * Creates a new {@link TargetTag}. - * - * @param targetTag - * to be created - * - * @return the new created {@link TargetTag} - * - * @throws EntityAlreadyExistsException - * if given object already exists - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) - public TargetTag createTargetTag(@NotNull final TargetTag targetTag) { - if (null != targetTag.getId()) { - throw new EntityAlreadyExistsException(); - } - - if (findTargetTag(targetTag.getName()) != null) { - throw new EntityAlreadyExistsException(); - } - - final TargetTag save = targetTagRepository.save(targetTag); - - afterCommit - .afterCommit(() -> eventBus.post(new TargetTagCreatedBulkEvent(tenantAware.getCurrentTenant(), save))); - - return save; - } - - /** - * created multiple {@link TargetTag}s. - * - * @param targetTags - * to be created - * @return the new created {@link TargetTag}s - * - * @throws EntityAlreadyExistsException - * if given object has already an ID. - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) - public List createTargetTags(@NotNull final Iterable targetTags) { - targetTags.forEach(tag -> { - if (tag.getId() != null) { - throw new EntityAlreadyExistsException(); - } - }); - final List save = targetTagRepository.save(targetTags); - afterCommit - .afterCommit(() -> eventBus.post(new TargetTagCreatedBulkEvent(tenantAware.getCurrentTenant(), save))); - return save; - } - - /** - * Deletes {@link TargetTag} with given name. - * - * @param targetTagName - * tag name of the {@link TargetTag} to be deleted - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET) - public void deleteTargetTag(@NotEmpty final String targetTagName) { - final TargetTag tag = targetTagRepository.findByNameEquals(targetTagName); - - final List changed = new LinkedList<>(); - for (final Target target : targetRepository.findByTag(tag)) { - target.getTags().remove(tag); - changed.add(target); - } - - // save association delete - targetRepository.save(changed); - - // finally delete the tag itself - targetTagRepository.deleteByName(targetTagName); - - afterCommit.afterCommit(() -> eventBus.post(new TargetTagDeletedEvent(tag))); - - } - - /** - * returns all {@link TargetTag}s. - * - * @return all {@link TargetTag}s - */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findAllTargetTags() { - return targetTagRepository.findAll(); - } - - /** - * Retrieves all target tags based on the given specification. - * - * @param spec - * the specification for the query - * @param pageable - * pagination parameter - * @return the found {@link Target}s, never {@code null} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Page findAllTargetTags(@NotNull final Specification spec, - @NotNull final Pageable pageable) { - return targetTagRepository.findAll(spec, pageable); - } - - /** - * count {@link TargetTag}s. - * - * @return size of {@link TargetTag}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public long countTargetTags() { - return targetTagRepository.count(); - } - - /** - * updates the {@link TargetTag}. - * - * @param targetTag - * the {@link TargetTag} - * @return the new {@link TargetTag} - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - public TargetTag updateTargetTag(@NotNull final TargetTag targetTag) { - checkNotNull(targetTag.getName()); - checkNotNull(targetTag.getId()); - final TargetTag save = targetTagRepository.save(targetTag); - afterCommit.afterCommit(() -> eventBus.post(new TargetTagUpdateEvent(save))); - return save; - } - - /** - * Find {@link DistributionSet} based on given name. - * - * @param name - * to look for. - * @return {@link DistributionSet} or null if it does not exist - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public DistributionSetTag findDistributionSetTag(@NotEmpty final String name) { - return distributionSetTagRepository.findByNameEquals(name); - } - - /** - * Creates a {@link DistributionSet}. - * - * @param distributionSetTag - * to be created. - * @return the new {@link DistributionSet} - * @throws EntityAlreadyExistsException - * if distributionSetTag already exists - * - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - public DistributionSetTag createDistributionSetTag(@NotNull final DistributionSetTag distributionSetTag) { - if (null != distributionSetTag.getId()) { - throw new EntityAlreadyExistsException(); - } - - if (distributionSetTagRepository.findByNameEquals(distributionSetTag.getName()) != null) { - throw new EntityAlreadyExistsException(); - } - - final DistributionSetTag save = distributionSetTagRepository.save(distributionSetTag); - - afterCommit.afterCommit( - () -> eventBus.post(new DistributionSetTagCreatedBulkEvent(tenantAware.getCurrentTenant(), save))); - return save; - } - - /** - * Creates multiple {@link DistributionSetTag}s. - * - * @param distributionSetTags - * to be created - * @return the new {@link DistributionSetTag} - * @throws EntityAlreadyExistsException - * if a given entity already exists - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - public List createDistributionSetTags( - @NotNull final Iterable distributionSetTags) { - for (final DistributionSetTag dsTag : distributionSetTags) { - if (dsTag.getId() != null) { - throw new EntityAlreadyExistsException(); - } - } - final List save = distributionSetTagRepository.save(distributionSetTags); - afterCommit.afterCommit( - () -> eventBus.post(new DistributionSetTagCreatedBulkEvent(tenantAware.getCurrentTenant(), save))); - - return save; - } - - /** - * Deletes {@link DistributionSetTag} by given - * {@link DistributionSetTag#getName()}. - * - * @param tagNames - * to be deleted - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - public void deleteDistributionSetTag(@NotEmpty final String tagName) { - final DistributionSetTag tag = distributionSetTagRepository.findByNameEquals(tagName); - - final List changed = new LinkedList<>(); - for (final DistributionSet set : distributionSetRepository.findByTag(tag)) { - set.getTags().remove(tag); - changed.add(set); - } - - // save association delete - distributionSetRepository.save(changed); - - distributionSetTagRepository.deleteByName(tagName); - - afterCommit.afterCommit(() -> eventBus.post(new DistributionSetTagDeletedEvent(tag))); - } - - /** - * Updates an existing {@link DistributionSetTag}. - * - * @param distributionSetTag - * to be updated - * @return the updated {@link DistributionSet} - * @throws NullPointerException - * of {@link DistributionSetTag#getName()} is null - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - public DistributionSetTag updateDistributionSetTag(@NotNull final DistributionSetTag distributionSetTag) { - checkNotNull(distributionSetTag.getName()); - checkNotNull(distributionSetTag.getId()); - final DistributionSetTag save = distributionSetTagRepository.save(distributionSetTag); - afterCommit.afterCommit(() -> eventBus.post(new DistributionSetTagUpdateEvent(save))); - - return save; - } - - /** - * returns all {@link DistributionTag}s. - * - * @return all {@link DistributionTag}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public List findAllDistributionSetTags() { - return distributionSetTagRepository.findAll(); - } - - /** - * Finds {@link TargetTag} by given id. - * - * @param id - * to search for - * @return the found {@link TargetTag}s or null if not found. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public TargetTag findTargetTagById(@NotNull final Long id) { - return targetTagRepository.findOne(id); - } - - /** - * Finds {@link DistributionSetTag} by given id. - * - * @param id - * to search for - * @return the found {@link DistributionSetTag}s or null if not - * found. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public DistributionSetTag findDistributionSetTagById(@NotNull final Long id) { - return distributionSetTagRepository.findOne(id); - } - - /** - * returns all {@link TargetTag}s. - * - * @param pageReq - * page parameter - * - * @return all {@link TargetTag}s - */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Page findAllTargetTags(@NotNull final Pageable pageReq) { - return targetTagRepository.findAll(pageReq); - } - - /** - * returns all {@link DistributionSetTag}s. - * - * @param pageReq - * page parameter - * @return all {@link DistributionSetTag}s - */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public Page findAllDistributionSetTags(@NotNull final Pageable pageReq) { - return distributionSetTagRepository.findAll(pageReq); - } - - /** - * Retrieves all DistributionSet tags based on the given specification. - * - * @param spec - * the specification for the query - * @param pageable - * pagination parameter - * @return the found {@link DistributionSetTag}s, never {@code null} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Page findAllDistributionSetTags(@NotNull final Specification spec, - @NotNull final Pageable pageable) { - return distributionSetTagRepository.findAll(spec, pageable); - } - -} 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 deleted file mode 100644 index 4f7c91da3..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository; - -import java.util.ArrayList; -import java.util.List; - -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.model.TargetFilterQuery; -import org.eclipse.hawkbit.repository.specifications.SpecificationsBuilder; -import org.eclipse.hawkbit.repository.specifications.TargetFilterQuerySpecification; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.domain.Specification; -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; - -import com.google.common.base.Strings; - -/** - * Business service facade for managing {@link TargetFilterQuery}s. - * - */ -@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -@Validated -@Service -public class TargetFilterQueryManagement { - - @Autowired - private TargetFilterQueryRepository targetFilterQueryRepository; - - /** - * creating new {@link TargetFilterQuery}. - * - * @param customTargetFilter - * @return the created {@link TargetFilterQuery} - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) - public TargetFilterQuery createTargetFilterQuery(@NotNull final TargetFilterQuery customTargetFilter) { - - if (targetFilterQueryRepository.findByName(customTargetFilter.getName()) != null) { - throw new EntityAlreadyExistsException(customTargetFilter.getName()); - } - return targetFilterQueryRepository.save(customTargetFilter); - } - - /** - * Delete target filter query. - * - * @param targetFilterQueryId - * IDs of target filter query to be deleted - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET) - public void deleteTargetFilterQuery(@NotNull final Long targetFilterQueryId) { - targetFilterQueryRepository.delete(targetFilterQueryId); - } - - /** - * - * Retrieves all target filter query{@link TargetFilterQuery}. - * - * @param pageable - * pagination parameter - * @return the found {@link TargetFilterQuery}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Page findAllTargetFilterQuery(@NotNull final Pageable pageable) { - return targetFilterQueryRepository.findAll(pageable); - } - - /** - * Retrieves all target filter query which {@link TargetFilterQuery}. - * - * - * @param pageable - * pagination parameter - * @param name - * target filter query name - * @return the page with the found {@link TargetFilterQuery} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Page findTargetFilterQueryByFilters(@NotNull final Pageable pageable, final String name) { - final List> specList = new ArrayList<>(); - if (!Strings.isNullOrEmpty(name)) { - specList.add(TargetFilterQuerySpecification.likeName(name)); - } - return findTargetFilterQueryByCriteriaAPI(pageable, specList); - } - - /** - * - * @param pageable - * pagination parameter - * @param specList - * list of @link {@link Specification} - * @return the page with the found {@link TargetFilterQuery} - */ - private Page findTargetFilterQueryByCriteriaAPI(@NotNull final Pageable pageable, - final List> specList) { - if (specList == null || specList.isEmpty()) { - return targetFilterQueryRepository.findAll(pageable); - } - - final Specifications specs = SpecificationsBuilder.combineWithAnd(specList); - return targetFilterQueryRepository.findAll(specs, pageable); - } - - /** - * Find target filter query by name. - * - * @param targetFilterQueryName - * Target filter query name - * @return the found {@link TargetFilterQuery} - * - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public TargetFilterQuery findTargetFilterQueryByName(@NotNull final String targetFilterQueryName) { - return targetFilterQueryRepository.findByName(targetFilterQueryName); - } - - /** - * Find target filter query by id. - * - * @param targetFilterQueryId - * Target filter query id - * @return the found {@link TargetFilterQuery} - * - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public TargetFilterQuery findTargetFilterQueryById(@NotNull final Long targetFilterQueryId) { - return targetFilterQueryRepository.findOne(targetFilterQueryId); - } - - /** - * updates the {@link TargetFilterQuery}. - * - * @param targetFilterQuery - * to be updated - * @return the updated {@link TargetFilterQuery} - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - public TargetFilterQuery updateTargetFilterQuery(@NotNull final TargetFilterQuery targetFilterQuery) { - Assert.notNull(targetFilterQuery.getId()); - return targetFilterQueryRepository.save(targetFilterQuery); - } - -} 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 deleted file mode 100644 index 4d6540acf..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java +++ /dev/null @@ -1,1110 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository; - -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -import javax.annotation.PreDestroy; -import javax.persistence.Entity; -import javax.persistence.EntityManager; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Expression; -import javax.persistence.criteria.Join; -import javax.persistence.criteria.JoinType; -import javax.persistence.criteria.Order; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.Constants; -import org.eclipse.hawkbit.eventbus.event.TargetTagAssigmentResultEvent; -import org.eclipse.hawkbit.executor.AfterTransactionCommitExecutor; -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSet_; -import org.eclipse.hawkbit.repository.model.Tag; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetFilterQuery; -import org.eclipse.hawkbit.repository.model.TargetIdName; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.hawkbit.repository.model.TargetInfo_; -import org.eclipse.hawkbit.repository.model.TargetTag; -import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult; -import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.repository.model.Target_; -import org.eclipse.hawkbit.repository.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.specifications.SpecificationsBuilder; -import org.eclipse.hawkbit.repository.specifications.TargetSpecifications; -import org.hibernate.validator.constraints.NotEmpty; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.data.domain.SliceImpl; -import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Sort.Direction; -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; - -import com.google.common.base.Strings; -import com.google.common.collect.Lists; -import com.google.common.eventbus.EventBus; - -/** - * Business service facade for managing {@link Target}s. - * - */ -@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -@Validated -@Service -public class TargetManagement { - - @Autowired - private EntityManager entityManager; - - @Autowired - private TargetRepository targetRepository; - - @Autowired - private TargetTagRepository targetTagRepository; - - @Autowired - private TargetInfoRepository targetInfoRepository; - - @Autowired - private NoCountPagingRepository criteriaNoCountDao; - - @Autowired - private EventBus eventBus; - - @Autowired - private AfterTransactionCommitExecutor afterCommit; - - /** - * Find {@link Target} based on given ID returns found Target without - * details, i.e. NO {@link Target#getTags()} and - * {@link Target#getActiveActions()} possible. - * - * @param controllerId - * to look for. - * @return {@link Target} or null if it does not exist - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Target findTargetByControllerID(@NotEmpty final String controllerId) { - return targetRepository.findByControllerId(controllerId); - } - - /** - * Find {@link Target} based on given ID returns found Target with details, - * i.e. {@link Target#getTags()} and {@link Target#getActiveActions()} are - * possible. - * - * Note: try to use {@link #findTargetByControllerID(String)} as much as - * possible. - * - * @param controllerId - * to look for. - * @return {@link Target} or null if it does not exist - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Target findTargetByControllerIDWithDetails(@NotEmpty final String controllerId) { - final Target result = targetRepository.findByControllerId(controllerId); - // load lazy relations - if (result != null) { - result.getTargetInfo().getControllerAttributes().size(); - if (result.getTargetInfo() != null && result.getTargetInfo().getInstalledDistributionSet() != null) { - result.getTargetInfo().getInstalledDistributionSet().getName(); - result.getTargetInfo().getInstalledDistributionSet().getModules().size(); - } - if (result.getAssignedDistributionSet() != null) { - result.getAssignedDistributionSet().getName(); - result.getAssignedDistributionSet().getModules().size(); - } - } - return result; - } - - /** - * Find {@link Target} based on given ID returns found Target without - * details, i.e. NO {@link Target#getTags()} and - * {@link Target#getActiveActions()} possible. - * - * @param controllerIDs - * to look for. - * @return List of found{@link Target}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findTargetByControllerID(@NotEmpty final Collection controllerIDs) { - return targetRepository.findAll(TargetSpecifications.byControllerIdWithStatusAndAssignedInJoin(controllerIDs)); - } - - /** - * Counts all {@link Target}s in the repository. - * - * @return number of targets - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Long countTargetsAll() { - return targetRepository.count(); - } - - /** - * Retrieves all targets without details, i.e. NO {@link Target#getTags()} - * and {@link Target#getActiveActions()} possible - * - * @param pageable - * pagination parameter - * @return the found {@link Target}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Slice findTargetsAll(@NotNull final Pageable pageable) { - // workarround - no join fetch allowed that is why we need specification - // instead of query for - // count() of Pageable - final Specification spec = (root, query, cb) -> { - if (!query.getResultType().isAssignableFrom(Long.class)) { - root.fetch(Target_.targetInfo); - } - return cb.conjunction(); - }; - return criteriaNoCountDao.findAll(spec, pageable, Target.class); - } - - /** - * Retrieves all targets without details, i.e. NO {@link Target#getTags()} - * and {@link Target#getActiveActions()} possible based on - * {@link TargetFilterQuery#getQuery()} - * - * @param targetFilterQuery - * @param pageable - * @return - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Slice findTargetsAll(@NotNull final TargetFilterQuery targetFilterQuery, - @NotNull final Pageable pageable) { - return findTargetsAll(RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class), pageable); - } - - /** - * Retrieves all targets without details, i.e. NO {@link Target#getTags()} - * and {@link Target#getActiveActions()} possible based on - * {@link TargetFilterQuery#getQuery()} - * - * @param targetFilterQuery - * @param pageable - * @return - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Slice findTargetsAll(@NotNull final String targetFilterQuery, @NotNull final Pageable pageable) { - return findTargetsAll(RSQLUtility.parse(targetFilterQuery, TargetFields.class), pageable); - } - - /** - * Retrieves all targets based on the given specification. - * - * @param spec - * the specification for the query - * @param pageable - * pagination parameter - * @return the found {@link Target}s, never {@code null} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Page findTargetsAll(@NotNull final Specification spec, @NotNull final Pageable pageable) { - return targetRepository.findAll(spec, pageable); - } - - /** - * retrieves a list of {@link Target}s by their controller ID with details, - * i.e. {@link Target#getTags()} are possible. - * - * Note: try to use {@link #findTargetByControllerID(String)} as much as - * possible. - * - * @param controllerIDs - * {@link Target}s Names parameter - * @return the found {@link Target}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findTargetsByControllerIDsWithTags(@NotNull final List controllerIDs) { - final List> partition = Lists.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT); - return partition.stream() - .map(ids -> targetRepository.findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(ids))) - .flatMap(t -> t.stream()).collect(Collectors.toList()); - } - - /** - * updates the {@link Target}. - * - * @param target - * to be updated - * @return the updated {@link Target} - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) - public Target updateTarget(@NotNull final Target target) { - Assert.notNull(target.getId()); - target.setNew(false); - return targetRepository.save(target); - } - - /** - * updates multiple {@link Target}s. - * - * @param targets - * to be updated - * @return the updated {@link Target}s - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) - public List updateTargets(@NotNull final List targets) { - targets.forEach(target -> target.setNew(false)); - return targetRepository.save(targets); - } - - /** - * Deletes all targets with the given IDs. - * - * @param targetIDs - * the technical IDs of the targets to be deleted - */ - @Modifying - @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 - // belonging to the - // tenant! Delete statement are not automatically enhanced with the - // @FilterDef of the - // hibernate session. - final List targetsForCurrentTenant = targetRepository.findAll(Lists.newArrayList(targetIDs)).stream() - .map(Target::getId).collect(Collectors.toList()); - if (!targetsForCurrentTenant.isEmpty()) { - targetInfoRepository.deleteByTargetIdIn(targetsForCurrentTenant); - targetRepository.deleteByIdIn(targetsForCurrentTenant); - } - } - - /** - * retrieves {@link Target}s by the assigned {@link DistributionSet} without - * details, i.e. NO {@link Target#getTags()} and - * {@link Target#getActiveActions()} possible. - * - * - * @param distributionSetID - * the ID of the {@link DistributionSet} - * @param pageReq - * page parameter - * @return the found {@link Target}s - */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET) - public Page findTargetByAssignedDistributionSet(@NotNull final Long distributionSetID, - @NotNull final Pageable pageReq) { - return targetRepository.findByAssignedDistributionSetId(pageReq, distributionSetID); - } - - /** - * Retrieves {@link Target}s by the assigned {@link DistributionSet} without - * details, i.e. NO {@link Target#getTags()} and - * {@link Target#getActiveActions()} possible including additional filtering - * based on the given {@code spec}. - * - * @param distributionSetID - * the ID of the {@link DistributionSet} - * @param spec - * the specification to filter the result set - * @param pageReq - * page parameter - * @return the found {@link Target}s, never {@code null} - */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET) - public Page findTargetByAssignedDistributionSet(@NotNull final Long distributionSetID, - final Specification spec, @NotNull final Pageable pageReq) { - return targetRepository.findAll((Specification) (root, query, cb) -> cb.and( - TargetSpecifications.hasAssignedDistributionSet(distributionSetID).toPredicate(root, query, cb), - spec.toPredicate(root, query, cb)), pageReq); - } - - /** - * retrieves {@link Target}s by the installed {@link DistributionSet}without - * details, i.e. NO {@link Target#getTags()} and - * {@link Target#getActiveActions()} possible. - * - * @param distributionSetID - * the ID of the {@link DistributionSet} - * @param pageReq - * page parameter - * @return the found {@link Target}s - */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET) - public Page findTargetByInstalledDistributionSet(@NotNull final Long distributionSetID, - @NotNull final Pageable pageReq) { - return targetRepository.findByTargetInfoInstalledDistributionSetId(pageReq, distributionSetID); - } - - /** - * retrieves {@link Target}s by the installed {@link DistributionSet}without - * details, i.e. NO {@link Target#getTags()} and - * {@link Target#getActiveActions()} possible including additional filtering - * based on the given {@code spec}. - * - * @param distributionSetId - * the ID of the {@link DistributionSet} - * @param spec - * the specification to filter the result - * @param pageable - * page parameter - * @return the found {@link Target}s, never {@code null} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET) - public Page findTargetByInstalledDistributionSet(final Long distributionSetId, - final Specification spec, final Pageable pageable) { - return targetRepository.findAll((Specification) (root, query, cb) -> cb.and( - TargetSpecifications.hasInstalledDistributionSet(distributionSetId).toPredicate(root, query, cb), - spec.toPredicate(root, query, cb)), pageable); - } - - /** - * Retrieves the {@link Target} which have a certain - * {@link TargetUpdateStatus} without details, i.e. NO - * {@link Target#getTags()} and {@link Target#getActiveActions()} possible. - * - * @param pageable - * page parameter - * @param status - * the {@link TargetUpdateStatus} to be filtered on - * @return the found {@link Target}s - */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Page findTargetByUpdateStatus(@NotNull final Pageable pageable, - @NotNull final TargetUpdateStatus status) { - return targetRepository.findByTargetInfoUpdateStatus(pageable, status); - } - - /** - * Filter {@link Target}s for all the given parameters. If all parameters - * except pageable are null, all available {@link Target}s are returned. - * - * @param pageable - * page parameters - * @param status - * find targets having this {@link TargetUpdateStatus}s. Set to - * null in case this is not required. - * @param searchText - * to find targets having the text anywhere in name or - * description. Set null in case this is not - * required. - * @param installedOrAssignedDistributionSetId - * to find targets having the {@link DistributionSet} as - * installed or assigned. Set to null in case this - * is not required. - * @param tagNames - * to find targets which are having any one in this tag names. - * Set null in case this is not required. - * @param selectTargetWithNoTag - * flag to select targets with no tag assigned - * - * @return the found {@link Target}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Slice findTargetByFilters(@NotNull final Pageable pageable, - final Collection status, final String searchText, - final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag, - final String... tagNames) { - final List> specList = buildSpecificationList(status, searchText, - installedOrAssignedDistributionSetId, selectTargetWithNoTag, true, tagNames); - return findByCriteriaAPI(pageable, specList); - } - - /** - * Count {@link Target}s for all the given filter parameters. - * - * @param status - * find targets having on of these {@link TargetUpdateStatus}s. - * Set to null in case this is not required. - * @param searchText - * to find targets having the text anywhere in name or - * description. Set null in case this is not - * required. - * @param installedOrAssignedDistributionSetId - * to find targets having the {@link DistributionSet} as - * installed or assigned. Set to null in case this - * is not required. - * @param tagNames - * to find targets which are having any one in this tag names. - * Set null in case this is not required. - * @param selectTargetWithNoTag - * flag to select targets with no tag assigned - * - * @return the found number {@link Target}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Long countTargetByFilters(final Collection status, final String searchText, - final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag, - final String... tagNames) { - final List> specList = buildSpecificationList(status, searchText, - installedOrAssignedDistributionSetId, selectTargetWithNoTag, true, tagNames); - return countByCriteriaAPI(specList); - } - - private static List> buildSpecificationList(final Collection status, - final String searchText, final Long installedOrAssignedDistributionSetId, - final Boolean selectTargetWithNoTag, final boolean fetch, final String... tagNames) { - final List> specList = new ArrayList<>(); - if (status != null && !status.isEmpty()) { - specList.add(TargetSpecifications.hasTargetUpdateStatus(status, fetch)); - } - if (installedOrAssignedDistributionSetId != null) { - specList.add( - TargetSpecifications.hasInstalledOrAssignedDistributionSet(installedOrAssignedDistributionSetId)); - } - if (!Strings.isNullOrEmpty(searchText)) { - specList.add(TargetSpecifications.likeNameOrDescriptionOrIp(searchText)); - } - if (selectTargetWithNoTag != null && (selectTargetWithNoTag || (tagNames != null && tagNames.length > 0))) { - specList.add(TargetSpecifications.hasTags(tagNames, selectTargetWithNoTag)); - } - return specList; - } - - /** - * executes findAll with the given {@link Target} {@link Specification}s. - * - * @param pageable - * paging parameter - * @param specList - * list of @link {@link Specification} - * @return the page with the found {@link Target} - */ - private Slice findByCriteriaAPI(final Pageable pageable, final List> specList) { - if (specList == null || specList.isEmpty()) { - return criteriaNoCountDao.findAll(pageable, Target.class); - } - return criteriaNoCountDao.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable, Target.class); - } - - private Long countByCriteriaAPI(final List> specList) { - if (specList == null || specList.isEmpty()) { - return targetRepository.count(); - } - - return targetRepository.count(SpecificationsBuilder.combineWithAnd(specList)); - } - - /** - * {@link Entity} based method call for - * {@link #toggleTagAssignment(Collection, String)}. - * - * @param targets - * to toggle for - * @param tag - * to toggle - * @return TagAssigmentResult with all metadata of the assignment outcome. - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - public TargetTagAssignmentResult toggleTagAssignment(@NotEmpty final List targets, - @NotNull final TargetTag tag) { - return toggleTagAssignment( - targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()), tag.getName()); - } - - /** - * Toggles {@link TargetTag} assignment to given {@link Target}s by means - * that if some (or all) of the targets in the list have the {@link Tag} not - * yet assigned, they will be. If all of theme have the tag already assigned - * they will be removed instead. - * - * @param targetIds - * to toggle for - * @param tagName - * to toogle - * @return TagAssigmentResult with all metadata of the assigment outcome. - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - public TargetTagAssignmentResult toggleTagAssignment(@NotEmpty final Collection targetIds, - @NotNull final String tagName) { - final TargetTag tag = targetTagRepository.findByNameEquals(tagName); - final List alreadyAssignedTargets = targetRepository.findByTagNameAndControllerIdIn(tagName, targetIds); - final List allTargets = targetRepository - .findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(targetIds)); - - // all are already assigned -> unassign - if (alreadyAssignedTargets.size() == allTargets.size()) { - alreadyAssignedTargets.forEach(target -> target.getTags().remove(tag)); - final TargetTagAssignmentResult result = new TargetTagAssignmentResult(0, 0, alreadyAssignedTargets.size(), - Collections.emptyList(), alreadyAssignedTargets, tag); - - afterCommit.afterCommit(() -> eventBus.post(new TargetTagAssigmentResultEvent(result))); - return result; - } - - allTargets.removeAll(alreadyAssignedTargets); - // some or none are assigned -> assign - allTargets.forEach(target -> target.getTags().add(tag)); - final TargetTagAssignmentResult result = new TargetTagAssignmentResult(alreadyAssignedTargets.size(), - allTargets.size(), 0, targetRepository.save(allTargets), Collections.emptyList(), tag); - - afterCommit.afterCommit(() -> eventBus.post(new TargetTagAssigmentResultEvent(result))); - - // no reason to persist the tag - entityManager.detach(tag); - return result; - } - - /** - * Assign a {@link TargetTag} assignment to given {@link Target}s. - * - * @param targetIds - * to assign for - * @param tagName - * to assign - * @return list of assigned targets - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - public List assignTag(@NotEmpty final Collection targetIds, @NotNull final TargetTag tag) { - final List allTargets = targetRepository - .findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(targetIds)); - - allTargets.forEach(target -> target.getTags().add(tag)); - final List save = targetRepository.save(allTargets); - - afterCommit.afterCommit(() -> { - final TargetTagAssignmentResult assigmentResult = new TargetTagAssignmentResult(0, save.size(), 0, save, - Collections.emptyList(), tag); - eventBus.post(new TargetTagAssigmentResultEvent(assigmentResult)); - }); - - return save; - } - - private List unAssignTag(@NotEmpty final Collection targets, @NotNull final TargetTag tag) { - targets.forEach(target -> target.getTags().remove(tag)); - - final List save = targetRepository.save(targets); - afterCommit.afterCommit(() -> { - final TargetTagAssignmentResult assigmentResult = new TargetTagAssignmentResult(0, 0, save.size(), - Collections.emptyList(), save, tag); - eventBus.post(new TargetTagAssigmentResultEvent(assigmentResult)); - }); - return save; - } - - /** - * Unassign all {@link Target} from a given {@link TargetTag} . - * - * @param tag - * to unassign all targets - * @return list of unassigned targets - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - public List unAssignAllTargetsByTag(@NotNull final TargetTag tag) { - return unAssignTag(tag.getAssignedToTargets(), tag); - } - - /** - * Unassign a {@link TargetTag} assignment to given {@link Target}. - * - * @param controllerID - * to unassign for - * @param targetTag - * to unassign - * @return the unassigned target or if no target is unassigned - */ - @Modifying - @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 - .findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(Arrays.asList(controllerID))); - final List unAssignTag = unAssignTag(allTargets, targetTag); - return unAssignTag.isEmpty() ? null : unAssignTag.get(0); - } - - /** - * method retrieves all {@link Target}s from the repo in the following - * order: - *

- * 1) {@link Target}s which have the given {@link DistributionSet} as - * {@link Target#getTargetStatus()} - * {@link TargetStatus#getInstalledDistributionSet()} - *

- * 2) {@link Target}s which have the given {@link DistributionSet} as - * {@link Target#getAssignedDistributionSet()} - *

- * 3) {@link Target}s which have no connection to the given - * {@link DistributionSet}. - * - * @param pageable - * the page request to page the result set - * @param orderByDistributionId - * {@link DistributionSet#getId()} to be ordered by - * @param filterByDistributionId - * {@link DistributionSet#getId()} to be filter the result. Set - * to null in case this is not required. - * @param filterByStatus - * find targets having this {@link TargetUpdateStatus}s. Set to - * null in case this is not required. - * @param filterBySearchText - * to find targets having the text anywhere in name or - * description. Set null in case this is not - * required. - * @param installedOrAssignedDistributionSetId - * to find targets having the {@link DistributionSet} as - * installed or assigned. Set to null in case this - * is not required. - * @param filterByTagNames - * to find targets which are having any one in this tag names. - * Set null in case this is not required. - * @param selectTargetWithNoTag - * flag to select targets with no tag assigned - * @return a paged result {@link Page} of the {@link Target}s in a defined - * order. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Slice findTargetsAllOrderByLinkedDistributionSet(@NotNull final Pageable pageable, - @NotNull final Long orderByDistributionId, final Long filterByDistributionId, - final Collection filterByStatus, final String filterBySearchText, - final Boolean selectTargetWithNoTag, final String... filterByTagNames) { - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - final CriteriaQuery query = cb.createQuery(Target.class); - final Root targetRoot = query.from(Target.class); - - // necessary joins for the select - final Join targetInfo = (Join) targetRoot.fetch(Target_.targetInfo, - JoinType.LEFT); - - // select case expression to retrieve the case value as a column to be - // able to order based on - // this column, installed first,... - final Expression selectCase = cb.selectCase() - .when(cb.equal(targetInfo.get(TargetInfo_.installedDistributionSet).get(DistributionSet_.id), - orderByDistributionId), 1) - .when(cb.equal(targetRoot.get(Target_.assignedDistributionSet).get(DistributionSet_.id), - orderByDistributionId), 2) - .otherwise(100); - // multiselect statement order by the select case and controllerId - query.distinct(true); - // build the specifications and then to predicates necessary by the - // given filters - final Predicate[] specificationsForMultiSelect = specificationsToPredicate( - buildSpecificationList(filterByStatus, filterBySearchText, filterByDistributionId, - selectTargetWithNoTag, true, filterByTagNames), - targetRoot, query, cb); - - // if we have some predicates then add it to the where clause of the - // multiselect - if (specificationsForMultiSelect.length > 0) { - query.where(specificationsForMultiSelect); - } - // add the order to the multi select first based on the selectCase - query.orderBy(cb.asc(selectCase), cb.desc(targetRoot.get(Target_.id))); - // the result is a Object[] due the fact that the selectCase is an extra - // column, so it cannot - // be mapped directly to a Target entity because the selectCase is not a - // attribute of the - // Target entity, the the Object array contains the Target on the first - // index (case of the - // multiselect order) of the array and - // the 2nd contains the selectCase int value. - final int pageSize = pageable.getPageSize(); - final List resultList = entityManager.createQuery(query).setFirstResult(pageable.getOffset()) - .setMaxResults(pageSize + 1).getResultList(); - final boolean hasNext = resultList.size() > pageSize; - return new SliceImpl<>(resultList, pageable, hasNext); - } - - /** - * @param specifications - */ - private static Predicate[] specificationsToPredicate(final List> specifications, - final Root root, final CriteriaQuery query, final CriteriaBuilder cb) { - final Predicate[] predicates = new Predicate[specifications.size()]; - for (int index = 0; index < predicates.length; index++) { - predicates[index] = specifications.get(index).toPredicate(root, query, cb); - } - return predicates; - } - - /** - * Counts number of targets with given - * {@link Target#getAssignedDistributionSet()}. - * - * @param distId - * to search for - * - * @return number of found {@link Target}s. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Long countTargetByAssignedDistributionSet(final Long distId) { - return targetRepository.countByAssignedDistributionSetId(distId); - } - - /** - * Counts number of targets with given - * {@link TargetStatus#getInstalledDistributionSet()}. - * - * @param distId - * to search for - * @return number of found {@link Target}s. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Long countTargetByInstalledDistributionSet(final Long distId) { - return targetRepository.countByTargetInfoInstalledDistributionSetId(distId); - } - - /** - * finds all {@link Target#getControllerId()} which are currently in the - * database. - * - * @return all IDs of all {@link Target} in the system - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findAllTargetIds() { - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - final CriteriaQuery query = cb.createQuery(TargetIdName.class); - final Root targetRoot = query.from(Target.class); - return entityManager.createQuery(query.multiselect(targetRoot.get(Target_.id), - targetRoot.get(Target_.controllerId), targetRoot.get(Target_.name))).getResultList(); - - } - - /** - * Finds all targets for all the given parameters but returns not the full - * target but {@link TargetIdName}. - * - * @param pageRequest - * the pageRequest to enhance the query for paging and sorting - * - * @param filterByStatus - * find targets having this {@link TargetUpdateStatus}s. Set to - * null in case this is not required. - * @param filterBySearchText - * to find targets having the text anywhere in name or - * description. Set null in case this is not - * required. - * @param installedOrAssignedDistributionSetId - * to find targets having the {@link DistributionSet} as - * installed or assigned. Set to null in case this - * is not required. - * @param filterByTagNames - * to find targets which are having any one in this tag names. - * Set null in case this is not required. - * @param selectTargetWithNoTag - * flag to select targets with no tag assigned - * - * @return the found {@link TargetIdName}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findAllTargetIdsByFilters(@NotNull final Pageable pageRequest, - final Collection filterByStatus, final String filterBySearchText, - final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag, - final String... filterByTagNames) { - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - final CriteriaQuery query = cb.createQuery(Object[].class); - final Root targetRoot = query.from(Target.class); - List resultList; - - String sortProperty = Target_.id.getName(); - if (pageRequest.getSort() != null && pageRequest.getSort().iterator().hasNext()) { - sortProperty = pageRequest.getSort().iterator().next().getProperty(); - } - - final CriteriaQuery multiselect = query.multiselect(targetRoot.get(Target_.id), - targetRoot.get(Target_.controllerId), targetRoot.get(Target_.name), targetRoot.get(sortProperty)); - - final Predicate[] specificationsForMultiSelect = specificationsToPredicate( - buildSpecificationList(filterByStatus, filterBySearchText, installedOrAssignedDistributionSetId, - selectTargetWithNoTag, false, filterByTagNames), - targetRoot, multiselect, cb); - - // if we have some predicates then add it to the where clause of the - // multiselect - if (specificationsForMultiSelect.length > 0) { - multiselect.where(specificationsForMultiSelect); - } - - resultList = getTargetIdNameResultSet(pageRequest, cb, targetRoot, multiselect); - return resultList.parallelStream().map(o -> new TargetIdName((long) o[0], o[1].toString(), o[2].toString())) - .collect(Collectors.toList()); - } - - /** - * Finds all targets for all the given parameter {@link TargetFilterQuery} - * and returns not the full target but {@link TargetIdName}. - * - * @param pageRequest - * the pageRequest to enhance the query for paging and sorting - * @param targetFilterQuery - * {@link TargetFilterQuery} - * @return the found {@link TargetIdName}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findAllTargetIdsByTargetFilterQuery(final Pageable pageRequest, - @NotNull final TargetFilterQuery targetFilterQuery) { - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - final CriteriaQuery query = cb.createQuery(Object[].class); - final Root targetRoot = query.from(Target.class); - - String sortProperty = Target_.id.getName(); - if (pageRequest.getSort() != null && pageRequest.getSort().iterator().hasNext()) { - sortProperty = pageRequest.getSort().iterator().next().getProperty(); - } - - final CriteriaQuery multiselect = query.multiselect(targetRoot.get(Target_.id), - targetRoot.get(Target_.controllerId), targetRoot.get(Target_.name), targetRoot.get(sortProperty)); - - final Specification spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class); - final List> specList = new ArrayList<>(); - specList.add(spec); - - final Predicate[] specificationsForMultiSelect = specificationsToPredicate(specList, targetRoot, multiselect, - cb); - - // if we have some predicates then add it to the where clause of the - // multiselect - if (specificationsForMultiSelect.length > 0) { - multiselect.where(specificationsForMultiSelect); - } - final List resultList = getTargetIdNameResultSet(pageRequest, cb, targetRoot, multiselect); - return resultList.parallelStream().map(o -> new TargetIdName((long) o[0], o[1].toString(), o[2].toString())) - .collect(Collectors.toList()); - } - - @PreDestroy - void destroy() { - eventBus.unregister(this); - } - - /** - * creating new {@link Target}s including poll status data. useful - * especially in plug and play scenarios. - * - * @param target - * to be created * - * @param status - * of the target - * @param lastTargetQuery - * if a plug and play case - * @param address - * if a plug and play case - * - * @throws EntityAlreadyExistsException - * - * @return - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) - @CacheEvict(value = { "targetsCreatedOverPeriod" }, allEntries = true) - public Target createTarget(@NotNull final Target target, @NotNull final TargetUpdateStatus status, - final Long lastTargetQuery, final URI address) { - - if (targetRepository.findByControllerId(target.getControllerId()) != null) { - throw new EntityAlreadyExistsException(target.getControllerId()); - } - - target.setNew(true); - final Target savedTarget = targetRepository.save(target); - final TargetInfo targetInfo = savedTarget.getTargetInfo(); - targetInfo.setUpdateStatus(status); - if (lastTargetQuery != null) { - targetInfo.setLastTargetQuery(lastTargetQuery); - } - if (address != null) { - targetInfo.setAddress(address.toString()); - } - targetInfo.setNew(true); - final Target targetToReturn = targetInfoRepository.save(targetInfo).getTarget(); - targetInfo.setNew(false); - return targetToReturn; - - } - - /** - * creating a new {@link Target}. - * - * @param target - * to be created - * @return the created {@link Target} - * - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) - @CacheEvict(value = { "targetsCreatedOverPeriod" }, allEntries = true) - public Target createTarget(@NotNull final Target target) { - return createTarget(target, TargetUpdateStatus.UNKNOWN, null, null); - } - - /** - * creates multiple {@link Target}s. If some of the given {@link Target}s - * already exists in the DB a {@link EntityAlreadyExistsException} is - * thrown. {@link Target}s contain all objects of the parameter targets, - * including duplicates. - * - * @param targets - * to be created. - * @return the created {@link Target}s - * - * @throws {@link - * EntityAlreadyExistsException} of one of the given targets - * already exist. - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) - public List createTargets(@NotNull final List targets) { - if (!targets.isEmpty() && targetRepository.countByControllerIdIn( - targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList())) > 0) { - throw new EntityAlreadyExistsException(); - } - final List savedTargets = new ArrayList<>(); - for (final Target t : targets) { - final Target myTarget = createTarget(t); - savedTargets.add(myTarget); - } - return savedTargets; - } - - /** - * creating a new {@link Target} including poll status data. useful - * especially in plug and play scenarios. - * - * @param targets - * to be created * - * @param status - * of the target - * @param lastTargetQuery - * if a plug and play case - * @param address - * if a plug and play case - * - * @return newly created target - */ - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) - public List createTargets(@NotNull final Collection targets, - @NotNull final TargetUpdateStatus status, final long lastTargetQuery, final URI address) { - if (targetRepository.countByControllerIdIn( - targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList())) > 0) { - throw new EntityAlreadyExistsException(); - } - final List savedTargets = new ArrayList<>(); - for (final Target t : targets) { - final Target myTarget = createTarget(t, status, lastTargetQuery, address); - savedTargets.add(myTarget); - } - return savedTargets; - } - - /** - * Find targets by tag name. - * - * @param tagName - * tag name - * @return list of matching targets - */ - @NotNull - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public List findTargetsByTag(@NotNull final String tagName) { - final TargetTag tag = targetTagRepository.findByNameEquals(tagName); - return targetRepository.findByTag(tag); - } - - /** - * Count {@link TargetFilterQuery}s for given filter parameter. - * - * @param targetFilterQuery - * {link TargetFilterQuery} - * @return the found number {@link TargetFilterQuery}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Long countTargetByTargetFilterQuery(@NotNull final TargetFilterQuery targetFilterQuery) { - final Specification specs = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class); - return targetRepository.count(specs); - } - - /** - * Count {@link TargetFilterQuery}s for given target filter query. - * - * @param targetFilterQuery - * {link TargetFilterQuery} - * @return the found number {@link TargetFilterQuery}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - public Long countTargetByTargetFilterQuery(@NotNull final String targetFilterQuery) { - final Specification specs = RSQLUtility.parse(targetFilterQuery, TargetFields.class); - return targetRepository.count(specs); - } - - private List getTargetIdNameResultSet(final Pageable pageRequest, final CriteriaBuilder cb, - final Root targetRoot, final CriteriaQuery multiselect) { - List resultList; - if (pageRequest.getSort() != null) { - final List orders = new ArrayList<>(); - final Sort sort = pageRequest.getSort(); - for (final Sort.Order sortOrder : sort) { - if (sortOrder.getDirection() == Direction.ASC) { - orders.add(cb.asc(targetRoot.get(sortOrder.getProperty()))); - } else { - orders.add(cb.desc(targetRoot.get(sortOrder.getProperty()))); - } - } - multiselect.orderBy(orders); - resultList = entityManager.createQuery(multiselect).setFirstResult(pageRequest.getOffset()) - .setMaxResults(pageRequest.getPageSize()).getResultList(); - } else { - resultList = entityManager.createQuery(multiselect).getResultList(); - } - return resultList; - } -} 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 deleted file mode 100644 index c292b39e3..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java +++ /dev/null @@ -1,271 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository; - -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.model.TenantConfiguration; -import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; -import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidatorException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.context.ApplicationContext; -import org.springframework.context.EnvironmentAware; -import org.springframework.core.convert.ConversionFailedException; -import org.springframework.core.convert.support.ConfigurableConversionService; -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, isolation = Isolation.READ_UNCOMMITTED) -@Validated -@Service -public class TenantConfigurationManagement implements EnvironmentAware { - - @Autowired - private TenantConfigurationRepository tenantConfigurationRepository; - - @Autowired - private ApplicationContext applicationContext; - - private final ConfigurableConversionService conversionService = new DefaultConversionService(); - - private Environment environment; - - /** - * Retrieves a configuration value from the e.g. tenant overwritten - * configuration values or in case the tenant does not a have a specific - * configuration the global default value hold in the {@link Environment}. - * - * @param - * the type of the configuration value - * @param configurationKey - * the key of the configuration - * @param propertyType - * the type of the configuration value, e.g. {@code String.class} - * , {@code Integer.class}, etc - * @return the converted configuration value either from the tenant specific - * configuration stored or from the fallback default values or - * {@code null} in case key has not been configured and not default - * value exists - * @throws TenantConfigurationValidatorException - * if the {@code propertyType} and the value in general does not - * match the expected type and format defined by the Key - * @throws ConversionFailedException - * if the property cannot be converted to the given - * {@code propertyType} - */ - - @Cacheable(value = "tenantConfiguration", key = "#configurationKey.getKeyName()") - @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_SYSTEM_CODE) - public TenantConfigurationValue getConfigurationValue(final TenantConfigurationKey configurationKey, - final Class propertyType) { - validateTenantConfigurationDataType(configurationKey, propertyType); - - final TenantConfiguration tenantConfiguration = tenantConfigurationRepository - .findByKey(configurationKey.getKeyName()); - - return buildTenantConfigurationValueByKey(configurationKey, propertyType, tenantConfiguration); - } - - /** - * Validates the data type of the tenant configuration. If it is possible to - * cast to the given data type. - * - * @param configurationKey - * the key - * @param propertyType - * the class - */ - protected void validateTenantConfigurationDataType(final TenantConfigurationKey configurationKey, - final Class propertyType) { - if (!configurationKey.getDataType().isAssignableFrom(propertyType)) { - throw new TenantConfigurationValidatorException( - String.format("Cannot parse the database value of type %s into the type %s.", - configurationKey.getDataType(), propertyType)); - } - } - - /** - * Build the tenant configuration by the given key - * - * @param configurationKey - * the key - * @param propertyType - * the property type - * @param tenantConfiguration - * the configuration - * @return if no default value is set and no database value available - * or returns the tenant configuration value - */ - protected TenantConfigurationValue buildTenantConfigurationValueByKey( - final TenantConfigurationKey configurationKey, final Class propertyType, - final TenantConfiguration tenantConfiguration) { - if (tenantConfiguration != null) { - return TenantConfigurationValue. builder().isGlobal(false).createdBy(tenantConfiguration.getCreatedBy()) - .createdAt(tenantConfiguration.getCreatedAt()) - .lastModifiedAt(tenantConfiguration.getLastModifiedAt()) - .lastModifiedBy(tenantConfiguration.getLastModifiedBy()) - .value(conversionService.convert(tenantConfiguration.getValue(), propertyType)).build(); - - } else if (configurationKey.getDefaultKeyName() != null) { - - return TenantConfigurationValue. builder().isGlobal(true).createdBy(null).createdAt(null) - .lastModifiedAt(null).lastModifiedBy(null) - .value(getGlobalConfigurationValue(configurationKey, propertyType)).build(); - } - return null; - } - - /** - * Retrieves a configuration value from the e.g. tenant overwritten - * configuration values or in case the tenant does not a have a specific - * configuration the global default value hold in the {@link Environment}. - * - * @param configurationKey - * the key of the configuration - * @return the converted configuration value either from the tenant specific - * configuration stored or from the fall back default values or - * {@code null} in case key has not been configured and not default - * value exists - * @throws TenantConfigurationValidatorException - * if the {@code propertyType} and the value in general does not - * match the expected type and format defined by the Key - * @throws ConversionFailedException - * if the property cannot be converted to the given - * {@code propertyType} - */ - @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()); - } - - /** - * returns the global configuration property either defined in the property - * file or an default value otherwise. - * - * @param - * the type of the configuration value - * @param configurationKey - * the key of the configuration - * @param propertyType - * the type of the configuration value, e.g. {@code String.class} - * , {@code Integer.class}, etc - * @return the global configured value - * @throws TenantConfigurationValidatorException - * if the {@code propertyType} and the value in the property - * file or the default value does not match the expected type - * and format defined by the Key - * @throws ConversionFailedException - * if the property cannot be converted to the given - * {@code propertyType} - */ - @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_SYSTEM_CODE) - public T getGlobalConfigurationValue(final TenantConfigurationKey configurationKey, - final Class propertyType) { - - if (!configurationKey.getDataType().isAssignableFrom(propertyType)) { - throw new TenantConfigurationValidatorException( - String.format("Cannot parse the database value of type %s into the type %s.", - configurationKey.getDataType(), propertyType)); - } - - final T valueInProperties = environment.getProperty(configurationKey.getDefaultKeyName(), propertyType); - - if (valueInProperties == null) { - return conversionService.convert(configurationKey.getDefaultValue(), propertyType); - } - - return valueInProperties; - } - - /** - * Adds or updates a specific configuration for a specific tenant. - * - * - * @param configurationKey - * the key of the configuration - * @param value - * the configuration value which will be written into the - * database. - * @return the configuration value which was just written into the database. - * @throws TenantConfigurationValidatorException - * if the {@code propertyType} and the value in general does not - * match the expected type and format defined by the Key - * @throws ConversionFailedException - * if the property cannot be converted to the given - */ - @CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()") - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) - public TenantConfigurationValue addOrUpdateConfiguration(final TenantConfigurationKey configurationKey, - final T value) { - - if (!configurationKey.getDataType().isAssignableFrom(value.getClass())) { - throw new TenantConfigurationValidatorException(String.format( - "Cannot parse the value %s of type %s into the type %s defined by the configuration key.", value, - value.getClass(), configurationKey.getDataType())); - } - - configurationKey.validate(applicationContext, value); - - TenantConfiguration tenantConfiguration = tenantConfigurationRepository - .findByKey(configurationKey.getKeyName()); - - if (tenantConfiguration == null) { - tenantConfiguration = new TenantConfiguration(configurationKey.getKeyName(), value.toString()); - } else { - tenantConfiguration.setValue(value.toString()); - } - - final TenantConfiguration updatedTenantConfiguration = tenantConfigurationRepository.save(tenantConfiguration); - - final Class clazzT = (Class) value.getClass(); - - return TenantConfigurationValue. builder().isGlobal(false) - .createdBy(updatedTenantConfiguration.getCreatedBy()) - .createdAt(updatedTenantConfiguration.getCreatedAt()) - .lastModifiedAt(updatedTenantConfiguration.getLastModifiedAt()) - .lastModifiedBy(updatedTenantConfiguration.getLastModifiedBy()) - .value(conversionService.convert(updatedTenantConfiguration.getValue(), clazzT)).build(); - } - - /** - * Deletes a specific configuration for the current tenant. Does nothing in - * case there is no tenant specific configuration value. - * - * @param configurationKey - * the configuration key to be deleted - */ - @CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()") - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) - public void deleteConfiguration(final TenantConfigurationKey configurationKey) { - tenantConfigurationRepository.deleteByKey(configurationKey.getKeyName()); - } - - @Override - public void setEnvironment(final Environment environment) { - this.environment = environment; - } -} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Action.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Action.java deleted file mode 100644 index eedb36037..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Action.java +++ /dev/null @@ -1,312 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository.model; - -import java.util.List; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.NamedEntityGraphs; -import javax.persistence.NamedSubgraph; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; - -import org.eclipse.hawkbit.cache.CacheField; -import org.eclipse.hawkbit.cache.CacheKeys; -import org.eclipse.persistence.annotations.CascadeOnDelete; - -/** - *

- * Applicable transition changes of the {@link SoftwareModule}s state of a - * {@link Target}, e.g. install, uninstall, update and preparations for the - * transition change, i.e. download. - *

- * - *

- * Actions are managed by the SP server and applied to the targets by the - * client. - *

- */ -@Table(name = "sp_action", indexes = { @Index(name = "sp_idx_action_01", columnList = "tenant,distribution_set"), - @Index(name = "sp_idx_action_02", columnList = "tenant,target,active"), - @Index(name = "sp_idx_action_prim", columnList = "tenant,id") }) -@NamedEntityGraphs({ @NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }), - @NamedEntityGraph(name = "Action.all", attributeNodes = { @NamedAttributeNode("distributionSet"), - @NamedAttributeNode(value = "target", subgraph = "target.ds") }, subgraphs = @NamedSubgraph(name = "target.ds", attributeNodes = @NamedAttributeNode("assignedDistributionSet"))) }) -@Entity -public class Action extends TenantAwareBaseEntity { - private static final long serialVersionUID = 1L; - - /** - * indicating that target action has no force time {@link #hasForcedTime()}. - */ - public static final long NO_FORCE_TIME = 0L; - - /** - * the {@link DistributionSet} which should be installed by this action. - */ - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_ds")) - private DistributionSet distributionSet; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_target")) - private Target target; - - @Column(name = "active") - private boolean active; - - @Column(name = "action_type", nullable = false) - @Enumerated(EnumType.STRING) - private ActionType actionType; - - @Column(name = "forced_time") - private long forcedTime; - - @Column(name = "status") - private Status status; - - @CascadeOnDelete - @OneToMany(mappedBy = "action", targetEntity = ActionStatus.class, fetch = FetchType.LAZY, cascade = { - CascadeType.REMOVE }) - private List actionStatus; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "rolloutgroup", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup")) - private RolloutGroup rolloutGroup; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout")) - private Rollout rollout; - - /** - * Note: filled only in {@link Status#DOWNLOAD}. - */ - @Transient - @CacheField(key = CacheKeys.DOWNLOAD_PROGRESS_PERCENT) - private int downloadProgressPercent; - - /** - * @return the distributionSet - */ - public DistributionSet getDistributionSet() { - return distributionSet; - } - - /** - * @param distributionSet - * the distributionSet to set - */ - public void setDistributionSet(final DistributionSet distributionSet) { - this.distributionSet = distributionSet; - } - - /** - * @return true when action is in state {@link Status#CANCELING} or - * {@link Status#CANCELED}, false otherwise - */ - public boolean isCancelingOrCanceled() { - return status == Status.CANCELING || status == Status.CANCELED; - } - - public void setActive(final boolean active) { - this.active = active; - } - - public Status getStatus() { - return status; - } - - public void setStatus(final Status status) { - this.status = status; - } - - public int getDownloadProgressPercent() { - return downloadProgressPercent; - } - - public void setDownloadProgressPercent(final int downloadProgressPercent) { - this.downloadProgressPercent = downloadProgressPercent; - } - - public boolean isActive() { - return active; - } - - public void setActionType(final ActionType actionType) { - this.actionType = actionType; - } - - /** - * @return the actionType - */ - public ActionType getActionType() { - return actionType; - } - - public List getActionStatus() { - return actionStatus; - } - - public void setTarget(final Target target) { - this.target = target; - } - - public Target getTarget() { - return target; - } - - public long getForcedTime() { - return forcedTime; - } - - public void setForcedTime(final long forcedTime) { - this.forcedTime = forcedTime; - } - - public RolloutGroup getRolloutGroup() { - return rolloutGroup; - } - - public void setRolloutGroup(final RolloutGroup rolloutGroup) { - this.rolloutGroup = rolloutGroup; - } - - public Rollout getRollout() { - return rollout; - } - - public void setRollout(final Rollout rollout) { - this.rollout = rollout; - } - - /** - * checks if the {@link #forcedTime} is hit by the given - * {@code hitTimeMillis}, by means if the given milliseconds are greater - * than the forcedTime. - * - * @param hitTimeMillis - * the milliseconds, mostly the - * {@link System#currentTimeMillis()} - * @return {@code true} if this {@link #type} is in - * {@link ActionType#TIMEFORCED} and the given {@code hitTimeMillis} - * is greater than the {@link #forcedTime} otherwise {@code false} - */ - public boolean isHitAutoForceTime(final long hitTimeMillis) { - if (actionType == ActionType.TIMEFORCED) { - return hitTimeMillis >= forcedTime; - } - return false; - } - - /** - * @return {@code true} if either the {@link #type} is - * {@link ActionType#FORCED} or {@link ActionType#TIMEFORCED} but - * then if the {@link #forcedTime} has been exceeded otherwise - * always {@code false} - */ - public boolean isForce() { - switch (actionType) { - case FORCED: - return true; - case TIMEFORCED: - return isHitAutoForceTime(System.currentTimeMillis()); - default: - return false; - } - } - - /** - * @return true when action is forced, false otherwise - */ - public boolean isForced() { - return actionType == ActionType.FORCED; - } - - @Override - public String toString() { - return "Action [distributionSet=" + distributionSet + ", getId()=" + getId() + "]"; - } - - /** - * Action status as reported by the controller. - * - * Be aware that JPA is persisting the ordinal number of the enum by means - * the ordered number in the enum. So don't re-order the enums within the - * Status enum declaration! - * - */ - public enum Status { - /** - * Action is finished successfully for this target. - */ - FINISHED, - - /** - * Action has failed for this target. - */ - ERROR, - - /** - * Action is still running but with warnings. - */ - WARNING, - - /** - * Action is still running for this target. - */ - RUNNING, - - /** - * Action has been canceled for this target. - */ - CANCELED, - - /** - * Action is in canceling state and waiting for controller confirmation. - */ - CANCELING, - - /** - * Action has been presented to the target. - */ - RETRIEVED, - - /** - * Action needs download by this target which has now started. - */ - DOWNLOAD, - - /** - * Action is in waiting state, e.g. the action is scheduled in a rollout - * but not yet activated. - */ - SCHEDULED; - } - - /** - * The action type for this action relation. - * - */ - public enum ActionType { - FORCED, SOFT, TIMEFORCED; - } -} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroup.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroup.java deleted file mode 100644 index 5aa30126c..000000000 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutGroup.java +++ /dev/null @@ -1,479 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository.model; - -import java.util.ArrayList; -import java.util.List; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.persistence.UniqueConstraint; - -/** - * JPA entity definition of persisting a group of an rollout. - * - * @author Michael Hirsch - * - */ -@Entity -@Table(name = "sp_rolloutgroup", indexes = { - @Index(name = "sp_idx_rolloutgroup_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { - "name", "rollout", "tenant" }, name = "uk_rolloutgroup")) -public class RolloutGroup extends NamedEntity { - - private static final long serialVersionUID = 1L; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolloutgroup_rollout")) - private Rollout rollout; - - @Column(name = "status") - private RolloutGroupStatus status = RolloutGroupStatus.READY; - - @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }) - @JoinColumn(name = "rolloutGroup_Id", insertable = false, updatable = false) - private final List rolloutTargetGroup = new ArrayList<>(); - - @ManyToOne(fetch = FetchType.LAZY) - private RolloutGroup parent; - - @Column(name = "success_condition", nullable = false) - private RolloutGroupSuccessCondition successCondition = RolloutGroupSuccessCondition.THRESHOLD; - - @Column(name = "success_condition_exp", length = 512, nullable = false) - private String successConditionExp = null; - - @Column(name = "success_action", nullable = false) - private RolloutGroupSuccessAction successAction = RolloutGroupSuccessAction.NEXTGROUP; - - @Column(name = "success_action_exp", length = 512, nullable = false) - private String successActionExp = null; - - @Column(name = "error_condition") - private RolloutGroupErrorCondition errorCondition = null; - - @Column(name = "error_condition_exp", length = 512) - private String errorConditionExp = null; - - @Column(name = "error_action") - private RolloutGroupErrorAction errorAction = null; - - @Column(name = "error_action_exp", length = 512) - private String errorActionExp = null; - - @Column(name = "total_targets") - private long totalTargets; - - @Transient - private transient TotalTargetCountStatus totalTargetCountStatus; - - public Rollout getRollout() { - return rollout; - } - - public void setRollout(final Rollout rollout) { - this.rollout = rollout; - } - - public RolloutGroupStatus getStatus() { - return status; - } - - public void setStatus(final RolloutGroupStatus status) { - this.status = status; - } - - public List getRolloutTargetGroup() { - return rolloutTargetGroup; - } - - public RolloutGroup getParent() { - return parent; - } - - public void setParent(final RolloutGroup parent) { - this.parent = parent; - } - - public RolloutGroupSuccessCondition getSuccessCondition() { - return successCondition; - } - - public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) { - successCondition = finishCondition; - } - - public String getSuccessConditionExp() { - return successConditionExp; - } - - public void setSuccessConditionExp(final String finishExp) { - successConditionExp = finishExp; - } - - public RolloutGroupErrorCondition getErrorCondition() { - return errorCondition; - } - - public void setErrorCondition(final RolloutGroupErrorCondition errorCondition) { - this.errorCondition = errorCondition; - } - - public String getErrorConditionExp() { - return errorConditionExp; - } - - public void setErrorConditionExp(final String errorExp) { - errorConditionExp = errorExp; - } - - public RolloutGroupErrorAction getErrorAction() { - return errorAction; - } - - public void setErrorAction(final RolloutGroupErrorAction errorAction) { - this.errorAction = errorAction; - } - - public String getErrorActionExp() { - return errorActionExp; - } - - public void setErrorActionExp(final String errorActionExp) { - this.errorActionExp = errorActionExp; - } - - public RolloutGroupSuccessAction getSuccessAction() { - return successAction; - } - - public String getSuccessActionExp() { - return successActionExp; - } - - public long getTotalTargets() { - return totalTargets; - } - - public void setTotalTargets(final long totalTargets) { - this.totalTargets = totalTargets; - } - - public void setSuccessAction(final RolloutGroupSuccessAction successAction) { - this.successAction = successAction; - } - - public void setSuccessActionExp(final String successActionExp) { - this.successActionExp = successActionExp; - } - - /** - * @return the totalTargetCountStatus - */ - public TotalTargetCountStatus getTotalTargetCountStatus() { - if (totalTargetCountStatus == null) { - totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); - } - return totalTargetCountStatus; - } - - /** - * @param totalTargetCountStatus - * the totalTargetCountStatus to set - */ - public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) { - this.totalTargetCountStatus = totalTargetCountStatus; - } - - @Override - public String toString() { - return "RolloutGroup [rollout=" + rollout + ", status=" + status + ", rolloutTargetGroup=" + rolloutTargetGroup - + ", parent=" + parent + ", finishCondition=" + successCondition + ", finishExp=" + successConditionExp - + ", errorCondition=" + errorCondition + ", errorExp=" + errorConditionExp + ", getName()=" + getName() - + ", getId()=" + getId() + "]"; - } - - /** - * Rollout goup state machine. - * - */ - public enum RolloutGroupStatus { - - /** - * Ready to start the group. - */ - READY, - - /** - * Group is scheduled and started sometime, e.g. trigger of group - * before. - */ - SCHEDULED, - - /** - * Group is finished. - */ - FINISHED, - - /** - * Group is finished and has errors. - */ - ERROR, - - /** - * Group is running. - */ - RUNNING; - } - - /** - * The condition to evaluate if an group is success state. - */ - public enum RolloutGroupSuccessCondition { - THRESHOLD("thresholdRolloutGroupSuccessCondition"); - - private final String beanName; - - private RolloutGroupSuccessCondition(final String beanName) { - this.beanName = beanName; - } - - /** - * @return the beanName - */ - public String getBeanName() { - return beanName; - } - } - - /** - * The condition to evaluate if an group is in error state. - */ - public enum RolloutGroupErrorCondition { - THRESHOLD("thresholdRolloutGroupErrorCondition"); - - private final String beanName; - - private RolloutGroupErrorCondition(final String beanName) { - this.beanName = beanName; - } - - /** - * @return the beanName - */ - public String getBeanName() { - return beanName; - } - } - - /** - * The actions executed when the {@link RolloutGroup#errorCondition} is hit. - */ - public enum RolloutGroupErrorAction { - PAUSE("pauseRolloutGroupAction"); - - private final String beanName; - - private RolloutGroupErrorAction(final String beanName) { - this.beanName = beanName; - } - - /** - * @return the beanName - */ - public String getBeanName() { - return beanName; - } - } - - /** - * The actions executed when the {@link RolloutGroup#successCondition} is - * hit. - */ - public enum RolloutGroupSuccessAction { - NEXTGROUP("startNextRolloutGroupAction"); - - private final String beanName; - - private RolloutGroupSuccessAction(final String beanName) { - this.beanName = beanName; - } - - /** - * @return the beanName - */ - public String getBeanName() { - return beanName; - } - } - - /** - * Object which holds all {@link RolloutGroup} conditions together which can - * easily built. - */ - public static class RolloutGroupConditions { - private RolloutGroupSuccessCondition successCondition = null; - private String successConditionExp = null; - private RolloutGroupSuccessAction successAction = null; - private String successActionExp = null; - private RolloutGroupErrorCondition errorCondition = null; - private String errorConditionExp = null; - private RolloutGroupErrorAction errorAction = null; - private String errorActionExp = null; - - public RolloutGroupSuccessCondition getSuccessCondition() { - return successCondition; - } - - public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) { - successCondition = finishCondition; - } - - public String getSuccessConditionExp() { - return successConditionExp; - } - - public void setSuccessConditionExp(final String finishConditionExp) { - successConditionExp = finishConditionExp; - } - - public RolloutGroupSuccessAction getSuccessAction() { - return successAction; - } - - public void setSuccessAction(final RolloutGroupSuccessAction successAction) { - this.successAction = successAction; - } - - public String getSuccessActionExp() { - return successActionExp; - } - - public void setSuccessActionExp(final String successActionExp) { - this.successActionExp = successActionExp; - } - - public RolloutGroupErrorCondition getErrorCondition() { - return errorCondition; - } - - public void setErrorCondition(final RolloutGroupErrorCondition errorCondition) { - this.errorCondition = errorCondition; - } - - public String getErrorConditionExp() { - return errorConditionExp; - } - - public void setErrorConditionExp(final String errorConditionExp) { - this.errorConditionExp = errorConditionExp; - } - - public RolloutGroupErrorAction getErrorAction() { - return errorAction; - } - - public void setErrorAction(final RolloutGroupErrorAction errorAction) { - this.errorAction = errorAction; - } - - public String getErrorActionExp() { - return errorActionExp; - } - - public void setErrorActionExp(final String errorActionExp) { - this.errorActionExp = errorActionExp; - } - } - - /** - * Builder to build easily the {@link RolloutGroupConditions}. - * - */ - public static class RolloutGroupConditionBuilder { - private final RolloutGroupConditions conditions = new RolloutGroupConditions(); - - public RolloutGroupConditions build() { - return conditions; - } - - /** - * Sets the finish condition and expression on the builder. - * - * @param condition - * the finish condition - * @param expression - * the finish expression - * @return the builder itself - */ - public RolloutGroupConditionBuilder successCondition(final RolloutGroupSuccessCondition condition, - final String expression) { - conditions.setSuccessCondition(condition); - conditions.setSuccessConditionExp(expression); - return this; - } - - /** - * Sets the success action and expression on the builder. - * - * @param action - * the success action - * @param expression - * the error expression - * @return the builder itself - */ - public RolloutGroupConditionBuilder successAction(final RolloutGroupSuccessAction action, - final String expression) { - conditions.setSuccessAction(action); - conditions.setSuccessActionExp(expression); - return this; - } - - /** - * Sets the error condition and expression on the builder. - * - * @param condition - * the error condition - * @param expression - * the error expression - * @return the builder itself - */ - public RolloutGroupConditionBuilder errorCondition(final RolloutGroupErrorCondition condition, - final String expression) { - conditions.setErrorCondition(condition); - conditions.setErrorConditionExp(expression); - return this; - } - - /** - * Sets the error action and expression on the builder. - * - * @param action - * the error action - * @param expression - * the error expression - * @return the builder itself - */ - public RolloutGroupConditionBuilder errorAction(final RolloutGroupErrorAction action, final String expression) { - conditions.setErrorAction(action); - conditions.setErrorActionExp(expression); - return this; - } - } -} diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/LocalH2TestDatabase.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/LocalH2TestDatabase.java deleted file mode 100644 index a32c481fc..000000000 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/LocalH2TestDatabase.java +++ /dev/null @@ -1,118 +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; - -import java.io.IOException; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.UUID; - -import org.h2.tools.Server; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - * - */ -public class LocalH2TestDatabase implements Testdatabase { - - private final static Logger LOG = LoggerFactory.getLogger(LocalH2TestDatabase.class); - private final int port; - private Server h2server; - private boolean dbStarted; - private String uri; - - public LocalH2TestDatabase(final int port) { - super(); - this.port = port; - createUri(); - initSystemProperties(); - } - - private final void initSystemProperties() { - System.setProperty("spring.datasource.driverClassName", getDriverClassName()); - System.setProperty("spring.datasource.username", ""); - System.setProperty("spring.datasource.password", ""); - System.setProperty("hawkbit.server.database", "H2"); - } - - private void dropAllObjects() { - try (Connection connection = DriverManager.getConnection(uri)) { - connection.prepareCall("DROP ALL OBJECTS;").execute(); - } catch (final SQLException e) { - e.printStackTrace(); - } - } - - @Override - public void before() { - try { - startDatabase(); - } catch (ClassNotFoundException | SQLException | IOException e) { - e.printStackTrace(); - } - } - - @Override - public void after() { - try { - stopDatabase(); - } catch (ClassNotFoundException | SQLException | IOException e) { - e.printStackTrace(); - } - } - - private void startDatabase() throws SQLException, ClassNotFoundException, IOException { - if (dbStarted) { - return; - } - - // Start H2 database for OpenFire - h2server = Server - .createTcpServer( - new String[] { "-tcpPort", String.valueOf(port), "-tcpAllowOthers", "-tcpShutdownForce" }) - .start(); - dbStarted = true; - LOG.info("H2 Database started on port {} and uri {}", port, uri); - dropAllObjects(); - } - - private final void createUri() { - this.uri = "jdbc:h2:tcp://localhost:" + port + "/mem:SP" + UUID.randomUUID().toString() + ";MVCC=TRUE;" - + "DB_CLOSE_DELAY=-1"; - System.setProperty("spring.datasource.url", uri); - } - - private void stopDatabase() throws SQLException, ClassNotFoundException, IOException { - if (!dbStarted) { - return; - } - - h2server.stop(); - h2server = null; - dbStarted = false; - try { - Thread.sleep(1000); - } catch (final InterruptedException e) { - } - } - - @Override - public String getDriverClassName() { - return "org.h2.Driver"; - } - - @Override - public String getUri() { - return uri; - } - -} diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestDataUtil.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestDataUtil.java deleted file mode 100644 index 1787d29e4..000000000 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestDataUtil.java +++ /dev/null @@ -1,366 +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; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Random; -import java.util.UUID; - -import org.apache.commons.io.IOUtils; -import org.eclipse.hawkbit.repository.ArtifactManagement; -import org.eclipse.hawkbit.repository.DistributionSetManagement; -import org.eclipse.hawkbit.repository.SoftwareManagement; -import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetTag; -import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetTag; - -import com.google.common.base.Strings; -import com.google.common.collect.Lists; - -import net._01001111.text.LoremIpsum; - -/** - * Data generator utility for tests. - * - * - * - */ -public class TestDataUtil { - private static final LoremIpsum LOREM = new LoremIpsum(); - - public static List generateDistributionSets(final String suffix, final int number, - final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement) { - - final List sets = new ArrayList(); - for (int i = 0; i < number; i++) { - sets.add(generateDistributionSet(suffix, "v1." + i, softwareManagement, distributionSetManagement, false)); - } - - return sets; - } - - public static DistributionSet generateDistributionSetWithNoSoftwareModules(final String name, final String version, - final DistributionSetManagement distributionSetManagement) { - - final DistributionSet dis = new DistributionSet(); - dis.setName(name); - dis.setVersion(version); - dis.setDescription("Test describtion for " + name); - return distributionSetManagement.createDistributionSet(dis); - } - - public static List generateDistributionSets(final int number, - final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement) { - - return generateDistributionSets("", number, softwareManagement, distributionSetManagement); - } - - public static DistributionSet generateDistributionSet(final String suffix, final String version, - final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement, - final boolean isRequiredMigrationStep) { - - final SoftwareModule ah = softwareManagement.createSoftwareModule(new SoftwareModule( - findOrCreateSoftwareModuleType(softwareManagement, "application"), suffix + "application", - version + "." + new Random().nextInt(100), LOREM.words(20), suffix + " vendor Limited, California")); - final SoftwareModule jvm = softwareManagement - .createSoftwareModule(new SoftwareModule(findOrCreateSoftwareModuleType(softwareManagement, "runtime"), - suffix + "app runtime", version + "." + new Random().nextInt(100), LOREM.words(20), - suffix + " vendor GmbH, Stuttgart, Germany")); - final SoftwareModule os = softwareManagement - .createSoftwareModule(new SoftwareModule(findOrCreateSoftwareModuleType(softwareManagement, "os"), - suffix + " Firmware", version + "." + new Random().nextInt(100), LOREM.words(20), - suffix + " vendor Limited Inc, California")); - - final List mand = new ArrayList<>(); - mand.add(findOrCreateSoftwareModuleType(softwareManagement, "os")); - - final List opt = new ArrayList<>(); - opt.add(findOrCreateSoftwareModuleType(softwareManagement, "application")); - opt.add(findOrCreateSoftwareModuleType(softwareManagement, "runtime")); - - return distributionSetManagement.createDistributionSet( - buildDistributionSet(suffix != null && suffix.length() > 0 ? suffix : "DS", version, - findOrCreateDistributionSetType(distributionSetManagement, "ecl_os_app_jvm", - "OS mandatory App/JVM optional", mand, opt), - os, jvm, ah).setRequiredMigrationStep(isRequiredMigrationStep)); - } - - public static DistributionSet generateDistributionSet(final String suffix, final String version, - final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement, - final Collection tags) { - - final DistributionSet set = generateDistributionSet(suffix, version, softwareManagement, - distributionSetManagement, false); - - final List sets = new ArrayList(); - sets.add(set); - - tags.forEach(tag -> distributionSetManagement.toggleTagAssignment(sets, tag)); - - return distributionSetManagement.findDistributionSetById(set.getId()); - - } - - public static List generateTargets(final int number) { - return generateTargets(0, number, "Test target "); - } - - public static List generateTargets(final int number, final String prefix) { - return generateTargets(0, number, prefix); - } - - public static List generateTargets(final int start, final int number, final String prefix) { - final List targets = new ArrayList<>(); - for (int i = start; i < start + number; i++) { - targets.add(new Target(prefix + i)); - } - - return targets; - } - - public static List generateTargetTags(final int number) { - final List result = new ArrayList<>(); - - for (int i = 0; i < number; i++) { - result.add(new TargetTag("tag" + i, "tagdesc" + i, "" + i)); - } - - return result; - } - - public static List generateDistributionSetTags(final int number) { - final List result = new ArrayList<>(); - - for (int i = 0; i < number; i++) { - result.add(new DistributionSetTag("tag" + i, "tagdesc" + i, "" + i)); - } - - return result; - } - - public static DistributionSet generateDistributionSet(final String suffix, - final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement, - final boolean isRequiredMigrationStep) { - return generateDistributionSet(suffix, "v1.0", softwareManagement, distributionSetManagement, - isRequiredMigrationStep); - } - - public static DistributionSet generateDistributionSet(final String suffix, - final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement) { - return generateDistributionSet(suffix, "v1.0", softwareManagement, distributionSetManagement, false); - } - - public static List generateArtifacts( - final ArtifactManagement artifactManagement, final Long moduleId) { - final List artifacts = new ArrayList<>(); - for (int i = 0; i < 3; i++) { - final InputStream stubInputStream = IOUtils.toInputStream("some test data" + i); - artifacts.add(artifactManagement.createLocalArtifact(stubInputStream, moduleId, "filename" + i, false)); - - } - - return artifacts; - } - - public static Target createTarget(final TargetManagement targetManagement) { - final String targetExist = "targetExist"; - final Target target = new Target(targetExist); - targetManagement.createTarget(target); - return target; - } - - public static DistributionSet generateDistributionSet(final String suffix, - final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement, - final Collection tags) { - return generateDistributionSet(suffix, "v1.0", softwareManagement, distributionSetManagement, tags); - } - - public static SoftwareModuleType findOrCreateSoftwareModuleType(final SoftwareManagement softwareManagement, - final String softwareModuleType) { - final SoftwareModuleType findSoftwareModuleTypeByKey = softwareManagement - .findSoftwareModuleTypeByKey(softwareModuleType); - if (findSoftwareModuleTypeByKey != null) { - return findSoftwareModuleTypeByKey; - } - return softwareManagement.createSoftwareModuleType(new SoftwareModuleType(softwareModuleType, - softwareModuleType, "Standard type " + softwareManagement, 1)); - } - - public static DistributionSetType findOrCreateDistributionSetType( - final DistributionSetManagement distributionSetManagement, final String dsTypeKey, final String dsTypeName, - final Collection mandatory, final Collection optional) { - final DistributionSetType findDistributionSetTypeByname = distributionSetManagement - .findDistributionSetTypeByKey(dsTypeKey); - - if (findDistributionSetTypeByname != null) { - return findDistributionSetTypeByname; - } - - final DistributionSetType type = new DistributionSetType(dsTypeKey, dsTypeName, "Standard type" + dsTypeName); - mandatory.forEach(entry -> type.addMandatoryModuleType(entry)); - optional.forEach(entry -> type.addOptionalModuleType(entry)); - - return distributionSetManagement.createDistributionSetType(type); - } - - /** - * builds a set of {@link Target} fixtures from the given parameters. - * - * @param noOfTgts - * number of targets to create - * @param ctlrIDPrefix - * prefix used for the controller ID - * @param descriptionPrefix - * prefix used for the description - * @return set of {@link Target} - */ - public static List buildTargetFixtures(final int noOfTgts, final String ctlrIDPrefix, - final String descriptionPrefix) { - return buildTargetFixtures(noOfTgts, ctlrIDPrefix, descriptionPrefix, null); - } - - /** - * method creates set of targets by by generating the controller ID and the - * description like: prefix + no of target. - * - * @param noOfTgts - * number of targets which should be created - * @param ctlrIDPrefix - * prefix of the controllerID which is concatenated with the - * number of the target - * @param descriptionPrefix - * prefix of the target description which is concatenated with - * the number of the target - * @param tags - * tags which should be added to the created {@link Target}s - * @return set of created targets - */ - public static List buildTargetFixtures(final int noOfTgts, final String ctlrIDPrefix, - final String descriptionPrefix, final TargetTag[] tags) { - final List list = new ArrayList(); - for (int i = 0; i < noOfTgts; i++) { - String ctrlID = ctlrIDPrefix; - if (Strings.isNullOrEmpty(ctrlID)) { - ctrlID = UUID.randomUUID().toString(); - } - ctrlID = String.format("%s-%05d", ctrlID, i); - - final String description = String.format("the description of ProvisioningTarget: [%s]", ctrlID); - - final Target target = buildTargetFixture(ctrlID, description, tags); - list.add(target); - - } - return list; - } - - /** - * builds a single {@link Target} fixture from the given parameters. - * - * @param ctrlID - * controllerID - * @param description - * the description of the target - * @param tags - * assigned {@link TargetTag}s - * @return the created {@link Target} - */ - public static Target buildTargetFixture(final String ctrlID, final String description, final TargetTag[] tags) { - final Target target = new Target(ctrlID); - target.setName("Prov.Target ".concat(ctrlID)); - target.setDescription(description); - if (tags != null && tags.length > 0) { - for (final TargetTag t : tags) { - target.getTags().add(t); - } - } - return target; - } - - /** - * builder method for creating a single target object. - * - * @param ctrlID - * the ID of the target - * @param description - * of the target - * @return the created target object - */ - public static Target buildTargetFixture(final String ctrlID, final String description) { - return buildTargetFixture(ctrlID, description, null); - } - - /** - * builder method for creating a {@link DistributionSet}. - * - * @param name - * of the DS - * @param version - * of the DS - * @param os - * operating system of the DS - * @param jvm - * java virtual machine of the DS - * @param agentHub - * of the DS - * @return the created {@link DistributionSet} - */ - public static DistributionSet buildDistributionSet(final String name, final String version, - final DistributionSetType type, final SoftwareModule os, final SoftwareModule jvm, - final SoftwareModule agentHub) { - final DistributionSet distributionSet = new DistributionSet(name, version, null, type, - Lists.newArrayList(os, jvm, agentHub)); - distributionSet.setDescription( - String.format("description of DistributionSet; name = '%s', version = '%s'", name, version)); - return distributionSet; - } - - /** - * builder method for creating a set of {@link TargetTag}. - * - * @param noOfTags - * number of {@link TargetTag}. to be created - * @param tagPrefix - * prefix for the {@link TargetTag.getName()} - * @return the created set of {@link TargetTag}s - */ - public static List buildTargetTagFixtures(final int noOfTags, final String tagPrefix) { - final List list = new ArrayList<>(); - for (int i = 0; i < noOfTags; i++) { - String tagName = "myTag"; - if (!Strings.isNullOrEmpty(tagPrefix)) { - tagName = tagPrefix; - } - tagName = String.format("%s-%05d", tagName, i); - - final TargetTag targetTag = buildTargetTagFixture(tagName); - list.add(targetTag); - } - return list; - } - - /** - * builder method for creating a simple {@link TargetTag}. - * - * @param tagName - * name of the Tag - * @return the {@link TargetTag} - */ - public static TargetTag buildTargetTagFixture(final String tagName) { - return new TargetTag(tagName); - } -} diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ControllerManagementTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ControllerManagementTest.java deleted file mode 100644 index 279932ef7..000000000 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ControllerManagementTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository; - -import static org.fest.assertions.api.Assertions.assertThat; -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.List; - -import javax.validation.ConstraintViolationException; - -import org.apache.commons.lang3.RandomStringUtils; -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.repository.model.ActionStatus; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.junit.Test; - -import ru.yandex.qatools.allure.annotations.Description; -import ru.yandex.qatools.allure.annotations.Features; -import ru.yandex.qatools.allure.annotations.Stories; - -@Features("Component Tests - Repository") -@Stories("Controller Management") -public class ControllerManagementTest extends AbstractIntegrationTest { - - @Test - @Description("Controller adds a new action status.") - public void controllerAddsActionStatus() { - final Target target = new Target("4712"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); - Target savedTarget = targetManagement.createTarget(target); - - final List toAssign = new ArrayList<>(); - toAssign.add(savedTarget); - - assertThat(savedTarget.getTargetInfo().getUpdateStatus()).isEqualTo(TargetUpdateStatus.UNKNOWN); - - savedTarget = deploymentManagement.assignDistributionSet(ds, toAssign).getAssignedEntity().iterator().next(); - final Action savedAction = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); - - assertThat(targetManagement.findTargetByControllerID(savedTarget.getControllerId()).getTargetInfo() - .getUpdateStatus()).isEqualTo(TargetUpdateStatus.PENDING); - - ActionStatus actionStatusMessage = new ActionStatus(savedAction, Action.Status.RUNNING, - System.currentTimeMillis()); - actionStatusMessage.addMessage("foobar"); - savedAction.setStatus(Status.RUNNING); - controllerManagament.addUpdateActionStatus(actionStatusMessage, savedAction); - assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getUpdateStatus()) - .isEqualTo(TargetUpdateStatus.PENDING); - - actionStatusMessage = new ActionStatus(savedAction, Action.Status.FINISHED, System.currentTimeMillis()); - actionStatusMessage.addMessage(RandomStringUtils.randomAscii(512)); - savedAction.setStatus(Status.FINISHED); - controllerManagament.addUpdateActionStatus(actionStatusMessage, savedAction); - assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getUpdateStatus()) - .isEqualTo(TargetUpdateStatus.IN_SYNC); - - assertThat(actionStatusRepository.findAll(pageReq).getNumberOfElements()).isEqualTo(3); - assertThat(deploymentManagement.findActionStatusByAction(pageReq, savedAction, false).getNumberOfElements()) - .isEqualTo(3); - } - - @Test - @Description("Register a controller which does not exist") - public void testfindOrRegisterTargetIfItDoesNotexist() { - final Target target = controllerManagament.findOrRegisterTargetIfItDoesNotexist("AA", null); - assertThat(target).as("target should not be null").isNotNull(); - - final Target sameTarget = controllerManagament.findOrRegisterTargetIfItDoesNotexist("AA", null); - assertThat(target).as("Target should be the equals").isEqualTo(sameTarget); - assertThat(targetRepository.count()).as("Only 1 target should be registred").isEqualTo(1L); - - // throws exception - try { - controllerManagament.findOrRegisterTargetIfItDoesNotexist("", null); - fail("should fail as target does not exist"); - } catch (final ConstraintViolationException e) { - - } - } - - @Test - @Description("Controller trys to finish an update process after it has been finished by an error action status.") - public void tryToFinishUpdateProcessMoreThenOnce() { - - // mock - final Target target = new Target("Rabbit"); - final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); - Target savedTarget = targetManagement.createTarget(target); - final List toAssign = new ArrayList<>(); - toAssign.add(savedTarget); - savedTarget = deploymentManagement.assignDistributionSet(ds, toAssign).getAssignedEntity().iterator().next(); - Action savedAction = deploymentManagement.findActiveActionsByTarget(savedTarget).get(0); - - // test and verify - final ActionStatus actionStatusMessage = new ActionStatus(savedAction, Action.Status.RUNNING, - System.currentTimeMillis()); - actionStatusMessage.addMessage("running"); - savedAction = controllerManagament.addUpdateActionStatus(actionStatusMessage, savedAction); - assertThat(targetManagement.findTargetByControllerID("Rabbit").getTargetInfo().getUpdateStatus()) - .isEqualTo(TargetUpdateStatus.PENDING); - - final ActionStatus actionStatusMessage2 = new ActionStatus(savedAction, Action.Status.ERROR, - System.currentTimeMillis()); - actionStatusMessage2.addMessage("error"); - savedAction = controllerManagament.addUpdateActionStatus(actionStatusMessage2, savedAction); - assertThat(targetManagement.findTargetByControllerID("Rabbit").getTargetInfo().getUpdateStatus()) - .isEqualTo(TargetUpdateStatus.ERROR); - - final ActionStatus actionStatusMessage3 = new ActionStatus(savedAction, Action.Status.FINISHED, - System.currentTimeMillis()); - actionStatusMessage3.addMessage("finish"); - controllerManagament.addUpdateActionStatus(actionStatusMessage3, savedAction); - - targetManagement.findTargetByControllerID("Rabbit").getTargetInfo().getUpdateStatus(); - - // test - assertThat(targetManagement.findTargetByControllerID("Rabbit").getTargetInfo().getUpdateStatus()) - .isEqualTo(TargetUpdateStatus.ERROR); - - } -} diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/utils/RepositoryDataGenerator.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/utils/RepositoryDataGenerator.java deleted file mode 100644 index a1c74e791..000000000 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/utils/RepositoryDataGenerator.java +++ /dev/null @@ -1,480 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository.utils; - -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.List; -import java.util.Random; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.IntStream; - -import javax.persistence.EntityManager; -import javax.persistence.Query; -import javax.transaction.Transactional; - -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; -import org.eclipse.hawkbit.repository.ControllerManagement; -import org.eclipse.hawkbit.repository.DeploymentManagement; -import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult; -import org.eclipse.hawkbit.repository.DistributionSetManagement; -import org.eclipse.hawkbit.repository.SoftwareManagement; -import org.eclipse.hawkbit.repository.TagManagement; -import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.repository.model.ActionStatus; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetTag; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetTag; -import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.util.IpUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.data.auditing.AuditingHandler; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.security.authentication.TestingAuthenticationToken; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.context.SecurityContextImpl; - -import net._01001111.text.LoremIpsum; - -/** - * Generates test data for setting up the repository for test or demonstration - * purpose. - * - * - * - */ -public final class RepositoryDataGenerator { - private static final Logger LOG = LoggerFactory.getLogger(RepositoryDataGenerator.class); - - public static void initDemoRepo(final ConfigurableApplicationContext context) { - final PersistentInitDemoDataBuilder initDemoDataBuilder = new PersistentInitDemoDataBuilder(context); - initDemoDataBuilder.initDemoRepo(20, 0); - } - - public static void initLoadRepo(final ConfigurableApplicationContext context) { - final PersistentInitDemoDataBuilder initDemoDataBuilder = new PersistentInitDemoDataBuilder(context); - initDemoDataBuilder.initDemoRepo(200, 200); - } - - /** - * builder which build initial demo data and stores it to the repos. - * - */ - private static final class PersistentInitDemoDataBuilder { - - private final SoftwareManagement softwareManagement; - private final TargetManagement targetManagement; - private final DeploymentManagement deploymentManagement; - private final TagManagement tagManagement; - private final ControllerManagement controllerManagement; - private final DistributionSetManagement distributionSetManagement; - - private final DatabaseCleanupUtil dbCleanupUtil; - - private final AuditingHandler auditingHandler; - - final LoremIpsum jlorem = new LoremIpsum(); - - PersistentInitDemoDataBuilder(final ConfigurableApplicationContext context) { - softwareManagement = context.getBean(SoftwareManagement.class); - targetManagement = context.getBean(TargetManagement.class); - tagManagement = context.getBean(TagManagement.class); - deploymentManagement = context.getBean(DeploymentManagement.class); - controllerManagement = context.getBean(ControllerManagement.class); - distributionSetManagement = context.getBean(DistributionSetManagement.class); - - dbCleanupUtil = context.getBean(DatabaseCleanupUtil.class); - - auditingHandler = context.getBean(AuditingHandler.class); - } - - private void runAsAllAuthorityContext(final Runnable runnable) { - final SecurityContext oldContext = SecurityContextHolder.getContext(); - try { - final SecurityContextImpl securityContextImpl = new SecurityContextImpl(); - final TestingAuthenticationToken authentication = new TestingAuthenticationToken("repogenator", - "repogenator", SpPermission.CREATE_REPOSITORY, SpPermission.CREATE_TARGET, - SpPermission.DELETE_REPOSITORY, SpPermission.DELETE_TARGET, SpPermission.READ_REPOSITORY, - SpPermission.READ_TARGET, SpPermission.UPDATE_REPOSITORY, SpPermission.UPDATE_TARGET, - SpringEvalExpressions.CONTROLLER_ROLE); - securityContextImpl.setAuthentication(authentication); - authentication.setDetails(new TenantAwareAuthenticationDetails("default", false)); - SecurityContextHolder.setContext(securityContextImpl); - runnable.run(); - } finally { - SecurityContextHolder.setContext(oldContext); - } - } - - public void generateTestTagetGroup(final String group, final int sizeMultiplikator) { - final DistributionSetTag dsTag = tagManagement - .createDistributionSetTag(new DistributionSetTag("For " + group + "s")); - - auditingHandler.setDateTimeProvider(() -> { - final Calendar instance = Calendar.getInstance(); - instance.add(Calendar.MONTH, -new Random().nextInt(7)); - - return instance; - }); - - final List targets = createTargetTestGroup(group, 20 * sizeMultiplikator); - - auditingHandler.setDateTimeProvider(() -> { - final Calendar instance = Calendar.getInstance(); - return instance; - }); - - LOG.debug("initDemoRepo - start now real action history for group: {}", group); - - // Old history of succesfully finished operations - IntStream.range(0, 10).forEach(idx -> { - final DistributionSet dsReal = TestDataUtil.generateDistributionSet(group + " Release", "v1." + idx, - softwareManagement, distributionSetManagement, - Arrays.asList(new DistributionSetTag[] { dsTag })); - - final DistributionSetAssignmentResult result = deploymentManagement.assignDistributionSet(dsReal, - targets); - - createSimpleActionStatusHistory(result.getActions()); - }); - - final List> targetGroups = splitIntoGroups(targets); - - IntStream.range(0, targetGroups.size()).forEach(idx -> { - final DistributionSet dsReal = TestDataUtil.generateDistributionSet(group + " Release", "v2." + idx, - softwareManagement, distributionSetManagement, - Arrays.asList(new DistributionSetTag[] { dsTag })); - - final DistributionSetAssignmentResult result = deploymentManagement.assignDistributionSet(dsReal, - targetGroups.get(idx)); - - createActionStatusHistory(result.getActions(), sizeMultiplikator); - }); - - LOG.debug("initDemoRepo - real action history finished for group: {}", group); - } - - private List> splitIntoGroups(final List allTargets) { - - final int elements = allTargets.size(); - - final int group1 = elements * (5 + new Random().nextInt(5)) / 100; - final int group2 = elements * (15 + new Random().nextInt(5)) / 100; - - final List> result = new ArrayList>(); - - result.add(allTargets.subList(0, group1)); - result.add(allTargets.subList(group1, group2)); - result.add(allTargets.subList(group2, elements)); - - return result; - - } - - private void createActionStatusHistory(final List actions, final int sizeMultiplikator) { - final AtomicInteger counter = new AtomicInteger(); - - int index = 0; - for (final Long actionGiven : actions) { - // retrieved - Action action = controllerManagement.registerRetrieved( - deploymentManagement.findActionWithDetails(actionGiven), - "Controller retrieved update action and should start now the download."); - - // download - final ActionStatus download = new ActionStatus(); - download.setAction(action); - download.setStatus(Status.DOWNLOAD); - download.addMessage("Controller started download."); - action = controllerManagement.addUpdateActionStatus(download, action); - - // warning - final ActionStatus warning = new ActionStatus(); - warning.setAction(action); - warning.setStatus(Status.WARNING); - warning.addMessage("Some warning: " + jlorem.words(new Random().nextInt(50))); - action = controllerManagement.addUpdateActionStatus(warning, action); - - // garbage - for (int i = 0; i < new Random().nextInt(10); i++) { - final ActionStatus running = new ActionStatus(); - running.setAction(action); - running.setStatus(Status.RUNNING); - running.addMessage("Still running: " + jlorem.words(new Random().nextInt(50))); - action = controllerManagement.addUpdateActionStatus(running, action); - for (int g = 0; g < new Random().nextInt(5); g++) { - final ActionStatus rand = new ActionStatus(); - rand.setAction(action); - rand.setStatus(Status.RUNNING); - rand.addMessage(jlorem.words(new Random().nextInt(50))); - action = controllerManagement.addUpdateActionStatus(rand, action); - } - } - - // close - final ActionStatus close = new ActionStatus(); - close.setAction(action); - - // with error - final int incrementAndGet = counter.incrementAndGet(); - if (incrementAndGet % 5 == 0) { - close.setStatus(Status.ERROR); - close.addMessage("Controller reported CLOSED with ERROR!"); - action = controllerManagement.addUpdateActionStatus(close, action); - } - // with OK - else { - close.setStatus(Status.FINISHED); - close.addMessage("Controller reported CLOSED with OK!"); - action = controllerManagement.addUpdateActionStatus(close, action); - } - - index++; - } - } - - private void createSimpleActionStatusHistory(final List actions) { - for (final Long actionGiven : actions) { - // retrieved - Action action = controllerManagement.registerRetrieved( - deploymentManagement.findActionWithDetails(actionGiven), - "Controller retrieved update action and should start now the download."); - - // close - final ActionStatus close = new ActionStatus(); - close.setAction(action); - close.setStatus(Status.FINISHED); - close.addMessage("Controller reported CLOSED with OK!"); - action = controllerManagement.addUpdateActionStatus(close, action); - - } - } - - private List createTargetTestGroup(final String group, final int targets) { - LOG.debug("createTargetTestGroup: create group {}", group); - - final TargetTag targTag = tagManagement.createTargetTag(new TargetTag(group)); - - final List targAs = targetManagement.createTargets(buildTargets(targets, group), - TargetUpdateStatus.REGISTERED, System.currentTimeMillis() - new Random().nextInt(50_000_000), - generateIPAddress()); - LOG.debug("createTargetTestGroup: {} created", group); - - LOG.debug("createTargetTestGroup: {} targets status updated including IP", group); - - return targetManagement.toggleTagAssignment(targAs, targTag).getAssignedEntity(); - } - - private List buildTargets(final int noOfTgts, final String descriptionPrefix) { - - final List result = new ArrayList(noOfTgts); - - for (int i = 0; i < noOfTgts; i++) { - final Target target = new Target(UUID.randomUUID().toString()); - - final StringBuilder builder = new StringBuilder(); - builder.append(descriptionPrefix); - builder.append(jlorem.words(5)); - - target.setDescription(builder.toString()); - target.getTargetInfo().getControllerAttributes().put("revision", "1.1"); - target.getTargetInfo().getControllerAttributes().put("capacity", "128M"); - target.getTargetInfo().getControllerAttributes().put("serial", - String.valueOf(System.currentTimeMillis())); - - result.add(target); - - } - - return result; - } - - /** - * method writes initial test/demo data to the repositories. - * - * @param sizeMultiplikator - * the entire scenario - * @param loadtestgroups - * packages of 1_000 targets - */ - private void initDemoRepo(final int sizeMultiplikator, final int loadtestgroups) { - final LoremIpsum jlorem = new LoremIpsum(); - - runAsAllAuthorityContext(() -> { - dbCleanupUtil.cleanupDB(null); - - // generate targets and assign DS - // 5 groups - 100 targets each -> 500 - final String[] targetTestGroups = { "SHC", "CCU", "Vehicle", "Vending machine", "ECU" }; - - final String[] modulesTypes = { "HeadUnit_FW", "EDC17_FW", "OSGi_Bundle" }; - - final DistributionSetTag depTag = tagManagement - .createDistributionSetTag(new DistributionSetTag("deprecated")); - - Arrays.stream(targetTestGroups).forEach(group -> { - generateTestTagetGroup(group, sizeMultiplikator); - }); - - // garbage DS - LOG.debug("initDemoRepo - start now DS garbage"); - TestDataUtil.generateDistributionSets("Generic Software Package", sizeMultiplikator, - softwareManagement, distributionSetManagement); - LOG.debug("initDemoRepo - DS garbage finished"); - - LOG.debug("initDemoRepo - start now Extra Software Modules and types"); - Arrays.stream(modulesTypes).forEach(typeName -> { - final SoftwareModuleType smtype = softwareManagement.createSoftwareModuleType( - new SoftwareModuleType(typeName.toLowerCase().replaceAll("\\s+", ""), typeName, - jlorem.words(5), Integer.MAX_VALUE)); - - for (int i1 = 0; i1 < sizeMultiplikator; i1++) { - softwareManagement.createSoftwareModule(new SoftwareModule(smtype, typeName + i1, "1.0." + i1, - jlorem.words(5), "the " + typeName + " vendor Inc.")); - } - - }); - LOG.debug("initDemoRepo - Extra Software Modules and types finished"); - - LOG.debug("initDemoRepo - start now target garbage"); - - // garbage targets - // unknown - targetManagement - .createTargets(TestDataUtil.generateTargets(targetTestGroups.length * sizeMultiplikator)); - - // registered - targetManagement.createTargets( - TestDataUtil.generateTargets(targetTestGroups.length * sizeMultiplikator, "registered"), - TargetUpdateStatus.REGISTERED, System.currentTimeMillis(), generateIPAddress()); - - // pending - final DistributionSetTag dsTag = tagManagement - .createDistributionSetTag(new DistributionSetTag("OnlyAssignedTag")); - final DistributionSet ds = TestDataUtil.generateDistributionSet("Pending DS", "v1.0", - softwareManagement, distributionSetManagement, - Arrays.asList(new DistributionSetTag[] { dsTag })); - deploymentManagement.assignDistributionSet(ds, targetManagement.createTargets( - TestDataUtil.generateTargets(targetTestGroups.length * sizeMultiplikator, "pending"))); - - // Load test means additional 1_000_000 target - - for (int i2 = 0; i2 < loadtestgroups; i2++) { - targetManagement.createTargets(TestDataUtil.generateTargets(i2 * 1_000, 1_000, "loadtest-")); - } - - LOG.debug("initDemoRepo complete"); - }); - } - /** - * Adding controller attributes for given {@link Target}. - */ - // private Target setControllerAttributes( final String targetId ) { - // final Target target = - // targetManagement.findTargetByControllerIDWithDetails( targetId ); - // target.getTargetStatus().getControllerAttributes().put( "revision", - // "1.1" ); - // target.getTargetStatus().getControllerAttributes().put( "capacity", - // "128M" ); - // target.getTargetStatus().getControllerAttributes().put( "serial", - // String.valueOf( - // System.currentTimeMillis()) ); - // return targetManagement.updateTarget( target ); - // } - } - - /** - * - * Data clean up class. - * - * - * - */ - public static class DatabaseCleanupUtil { - - private static final Logger LOG = LoggerFactory.getLogger(DatabaseCleanupUtil.class); - @Autowired - private EntityManager entityManager; - - private static final String[] CLEAN_UP_SQLS = new String[] { "sp_tenant", "sp_tenant_configuration", - "sp_artifact", "sp_external_artifact", "sp_external_provider", "sp_target_target_tag", - "sp_target_attributes", "sp_target_tag", "sp_action_status_messages", "sp_action_status", "sp_action", - "sp_ds_dstag", "sp_distributionset_tag", "sp_target_info", "sp_target", "sp_sw_metadata", - "sp_ds_metadata", "sp_ds_module", "sp_distribution_set", "sp_base_software_module", - "sp_ds_type_element", "sp_distribution_set_type", "sp_software_module_type" }; - - /** - * delete all entries from the DB tables. - */ - @Transactional - @Modifying - public void cleanupDB(final String database) { - LOG.debug("Data clean up is started..."); - final boolean isMySql = "MYSQL".equals(database); - if (isMySql) { - // disable foreign key check because otherwise mysql cannot - // delete sp_active_actions due - // the self constraint within the table, stupid MySql - entityManager.createNativeQuery("SET FOREIGN_KEY_CHECKS = 0").executeUpdate(); - } - try { - final String[] dbCmds = new String[] { "delete from" }; - for (final String dbCmd : dbCmds) { - for (final String table : CLEAN_UP_SQLS) { - final String sql = String.format("%s %s", dbCmd, table); - final Query query = entityManager.createNativeQuery(sql); - try { - LOG.debug("cleanup table: {}", sql); - LOG.debug("cleaned table: {}; deleted {} records", sql, query.executeUpdate()); - } catch (final Exception ex) { - LOG.error(String.format("error on executing cleanup statement '%s'", sql), ex); - throw ex; - } - } - } - - LOG.debug("Data clean up is finished..."); - } finally { - if (isMySql) { - // enable foreign key check again! - entityManager.createNativeQuery("SET FOREIGN_KEY_CHECKS = 1").executeUpdate(); - } - } - } - } - - /** - * @return a generated IPv4 address string. - */ - private static URI generateIPAddress() { - final Random r = new Random(); - return IpUtil - .createHttpUri(r.nextInt(256) + "." + r.nextInt(256) + "." + r.nextInt(256) + "." + r.nextInt(256)); - } - - private RepositoryDataGenerator() { - super(); - } - -} diff --git a/hawkbit-rest-core/pom.xml b/hawkbit-rest-core/pom.xml new file mode 100644 index 000000000..bb511839c --- /dev/null +++ b/hawkbit-rest-core/pom.xml @@ -0,0 +1,103 @@ + + + 4.0.0 + + org.eclipse.hawkbit + hawkbit-parent + 0.2.0-SNAPSHOT + + hawkbit-rest-core + hawkBit :: REST Core + + + + + org.eclipse.hawkbit + hawkbit-repository-api + ${project.version} + + + org.eclipse.hawkbit + hawkbit-repository-jpa + ${project.version} + + + org.eclipse.hawkbit + hawkbit-core + ${project.version} + + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-databind + + + javax.servlet + javax.servlet-api + provided + + + org.apache.tomcat.embed + tomcat-embed-core + provided + + + + + org.eclipse.hawkbit + hawkbit-repository-test + ${project.version} + test + + + org.easytesting + fest-assert + test + + + ru.yandex.qatools.allure + allure-junit-adaptor + test + + + org.springframework.boot + spring-boot-starter-test + test + + + org.json + json + test + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + + \ No newline at end of file diff --git a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/configuration/RestConfiguration.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/configuration/RestConfiguration.java new file mode 100644 index 000000000..e2c4ec2a1 --- /dev/null +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/configuration/RestConfiguration.java @@ -0,0 +1,52 @@ +/** + * 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.rest.configuration; + +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.hawkbit.rest.util.FilterHttpResponse; +import org.eclipse.hawkbit.rest.util.HttpResponseFactoryBean; +import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.web.context.WebApplicationContext; + +/** + * Configuration for Rest api. + */ +@Configuration +public class RestConfiguration { + + /** + * Create filter for {@link HttpServletResponse}. + */ + @Bean + public FilterHttpResponse filterHttpResponse() { + return new FilterHttpResponse(); + } + + /** + * Create factory bean for {@link HttpServletResponse}. + */ + @Bean + public FactoryBean httpResponseFactoryBean() { + return new HttpResponseFactoryBean(); + } + + /** + * Create factory bean for {@link HttpServletResponse}. + */ + @Bean + @Scope(value = WebApplicationContext.SCOPE_REQUEST) + public RequestResponseContextHolder requestResponseContextHolder() { + return new RequestResponseContextHolder(); + } +} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortDirection.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/data/SortDirection.java similarity index 89% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortDirection.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/data/SortDirection.java index 344c27ce7..ca33d25b3 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortDirection.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/data/SortDirection.java @@ -6,7 +6,9 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.rest.data; + +import org.eclipse.hawkbit.rest.exception.SortParameterUnsupportedDirectionException; /** * A definition of possible sorting direction. diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/MessageNotReadableException.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/MessageNotReadableException.java similarity index 95% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/MessageNotReadableException.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/MessageNotReadableException.java index 023b67352..3c5e0aee3 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/MessageNotReadableException.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/MessageNotReadableException.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.rest.exception; import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.exception.SpServerRtException; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/ResponseExceptionHandler.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/ResponseExceptionHandler.java similarity index 78% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/ResponseExceptionHandler.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/ResponseExceptionHandler.java index 25ddc7c4c..02a48ef78 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/ResponseExceptionHandler.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/ResponseExceptionHandler.java @@ -6,17 +6,19 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.rest.exception; import java.util.EnumMap; +import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; -import org.apache.tomcat.util.http.fileupload.FileUploadBase.FileSizeLimitExceededException; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.exception.SpServerRtException; -import org.eclipse.hawkbit.rest.resource.model.ExceptionInfo; +import org.eclipse.hawkbit.repository.exception.MultiPartFileUploadException; +import org.eclipse.hawkbit.rest.json.model.ExceptionInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; @@ -26,12 +28,10 @@ import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.multipart.MultipartException; +import com.google.common.collect.Iterables; + /** * General controller advice for exception handling. - * - * - * - * */ @ControllerAdvice public class ResponseExceptionHandler { @@ -67,6 +67,7 @@ public class ResponseExceptionHandler { ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ROLLOUT_ILLEGAL_STATE, HttpStatus.BAD_REQUEST); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_CONFIGURATION_VALUE_INVALID, HttpStatus.BAD_REQUEST); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_CONFIGURATION_KEY_INVALID, HttpStatus.BAD_REQUEST); + ERROR_TO_HTTP_STATUS.put(SpServerError.SP_REPO_INVALID_TARGET_ADDRESS, HttpStatus.BAD_REQUEST); } private static HttpStatus getStatusOrDefault(final SpServerError error) { @@ -86,15 +87,13 @@ public class ResponseExceptionHandler { * as entity. */ @ExceptionHandler(SpServerRtException.class) - public ResponseEntity handleSpServerRtExceptions(final HttpServletRequest request, final Exception ex) { - LOG.debug("Handling exception of request {}", request.getRequestURL()); - final ExceptionInfo response = new ExceptionInfo(); + public ResponseEntity handleSpServerRtExceptions(final HttpServletRequest request, + final Exception ex) { + logRequest(request, ex); + final ExceptionInfo response = createExceptionInfo(ex); final HttpStatus responseStatus; - response.setMessage(ex.getMessage()); - response.setExceptionClass(ex.getClass().getName()); if (ex instanceof SpServerRtException) { responseStatus = getStatusOrDefault(((SpServerRtException) ex).getError()); - response.setErrorCode(((SpServerRtException) ex).getError().getKey()); } else { responseStatus = DEFAULT_RESPONSE_STATUS; } @@ -116,11 +115,8 @@ public class ResponseExceptionHandler { @ExceptionHandler(HttpMessageNotReadableException.class) public ResponseEntity handleHttpMessageNotReadableException(final HttpServletRequest request, final Exception ex) { - LOG.debug("Handling exception {} of request {}", ex.getClass().getName(), request.getRequestURL()); - final ExceptionInfo response = new ExceptionInfo(); - response.setErrorCode(SpServerError.SP_REST_BODY_NOT_READABLE.getKey()); - response.setMessage(SpServerError.SP_REST_BODY_NOT_READABLE.getMessage()); - response.setExceptionClass(MessageNotReadableException.class.getName()); + logRequest(request, ex); + final ExceptionInfo response = createExceptionInfo(new MessageNotReadableException()); return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } @@ -137,35 +133,30 @@ public class ResponseExceptionHandler { * as entity. */ @ExceptionHandler(MultipartException.class) - public ResponseEntity handleFileLimitExceededException(final HttpServletRequest request, + public ResponseEntity handleMultipartException(final HttpServletRequest request, final Exception ex) { - LOG.debug("Handling exception {} of request {}", ex.getClass().getName(), request.getRequestURL()); - final ExceptionInfo response = new ExceptionInfo(); - - if (searchForCause(ex, FileSizeLimitExceededException.class)) { - response.setErrorCode(SpServerError.SP_ARTIFACT_UPLOAD_FILE_LIMIT_EXCEEDED.getKey()); - response.setMessage(SpServerError.SP_ARTIFACT_UPLOAD_FILE_LIMIT_EXCEEDED.getMessage()); - response.setExceptionClass(FileSizeLimitExceededException.class.getName()); - } else { - response.setErrorCode(SpServerError.SP_ARTIFACT_UPLOAD_FAILED.getKey()); - response.setMessage(SpServerError.SP_ARTIFACT_UPLOAD_FAILED.getMessage()); - response.setExceptionClass(MultipartException.class.getName()); - } + logRequest(request, ex); + final List throwables = ExceptionUtils.getThrowableList(ex); + final Throwable responseCause = Iterables.getLast(throwables); + final ExceptionInfo response = createExceptionInfo(new MultiPartFileUploadException(responseCause)); return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } - private static boolean searchForCause(final Throwable t, final Class lookFor) { - if (t != null && t.getCause() != null) { - if (t.getCause().getClass().isAssignableFrom(lookFor)) { - return true; - } else { - return searchForCause(t.getCause(), lookFor); - } + private void logRequest(final HttpServletRequest request, final Exception ex) { + LOG.debug("Handling exception {} of request {}", ex.getClass().getName(), request.getRequestURL()); + } + + private ExceptionInfo createExceptionInfo(final Exception ex) { + final ExceptionInfo response = new ExceptionInfo(); + response.setMessage(ex.getMessage()); + response.setExceptionClass(ex.getClass().getName()); + if (ex instanceof SpServerRtException) { + response.setErrorCode(((SpServerRtException) ex).getError().getKey()); } - return false; + return response; } } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortParameterSyntaxErrorException.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/SortParameterSyntaxErrorException.java similarity index 95% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortParameterSyntaxErrorException.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/SortParameterSyntaxErrorException.java index b6bacd9d2..a8d476ac1 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortParameterSyntaxErrorException.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/SortParameterSyntaxErrorException.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.rest.exception; import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.exception.SpServerRtException; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortParameterUnsupportedDirectionException.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/SortParameterUnsupportedDirectionException.java similarity index 97% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortParameterUnsupportedDirectionException.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/SortParameterUnsupportedDirectionException.java index 60fa3d8df..b44b94917 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortParameterUnsupportedDirectionException.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/SortParameterUnsupportedDirectionException.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.rest.exception; import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.exception.SpServerRtException; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortParameterUnsupportedFieldException.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/SortParameterUnsupportedFieldException.java similarity index 97% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortParameterUnsupportedFieldException.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/SortParameterUnsupportedFieldException.java index 20c6f03d6..c9ce0dcdd 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortParameterUnsupportedFieldException.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/SortParameterUnsupportedFieldException.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.rest.exception; import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.exception.SpServerRtException; diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/ExceptionInfo.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/json/model/ExceptionInfo.java similarity index 97% rename from hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/ExceptionInfo.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/json/model/ExceptionInfo.java index e2d808943..d68e0037f 100644 --- a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/model/ExceptionInfo.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/json/model/ExceptionInfo.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model; +package org.eclipse.hawkbit.rest.json.model; import java.util.List; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/helper/ByteRange.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/ByteRange.java similarity index 98% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/helper/ByteRange.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/ByteRange.java index df72e2c53..667fc197d 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/helper/ByteRange.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/ByteRange.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.helper; +package org.eclipse.hawkbit.rest.util; /** * Byte range for resume download operations. diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/FileSteamingFailedException.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/FileSteamingFailedException.java similarity index 90% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/FileSteamingFailedException.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/FileSteamingFailedException.java index b4dae3b88..abf7c0245 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/FileSteamingFailedException.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/FileSteamingFailedException.java @@ -6,22 +6,16 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.controller; +package org.eclipse.hawkbit.rest.util; import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.exception.SpServerRtException; /** * Thrown if artifact content streaming to client failed. - * - * - * - * */ public final class FileSteamingFailedException extends SpServerRtException { - /** - * - */ + private static final long serialVersionUID = 1L; /** @@ -33,6 +27,8 @@ public final class FileSteamingFailedException extends SpServerRtException { } /** + * Constructor with Throwable. + * * @param cause * for the exception */ @@ -41,6 +37,8 @@ public final class FileSteamingFailedException extends SpServerRtException { } /** + * Constructor with error string. + * * @param message * of the error */ diff --git a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/FilterHttpResponse.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/FilterHttpResponse.java new file mode 100644 index 000000000..7620e7404 --- /dev/null +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/FilterHttpResponse.java @@ -0,0 +1,54 @@ +/** + * 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.rest.util; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +/** + * Filter is needed to autowire the {@link HttpServletResponse}. + * + */ +public class FilterHttpResponse implements Filter { + + private ThreadLocal threadLocalResponse = new ThreadLocal<>(); + + @Override + public void init(final FilterConfig filterConfig) throws ServletException { + // not needed + } + + @Override + public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) + throws IOException, ServletException { + try { + threadLocalResponse.set((HttpServletResponse) response); + chain.doFilter(request, response); + } finally { + threadLocalResponse.remove(); + } + } + + public HttpServletResponse getHttpServletReponse() { + return threadLocalResponse.get(); + } + + @Override + public void destroy() { + threadLocalResponse = null; + } + +} diff --git a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/HttpResponseFactoryBean.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/HttpResponseFactoryBean.java new file mode 100644 index 000000000..6df7987e6 --- /dev/null +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/HttpResponseFactoryBean.java @@ -0,0 +1,55 @@ +/** + * 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.rest.util; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.NamedBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * + * Factory bean to autowire the {@link HttpServletResponse}. + * + */ +public class HttpResponseFactoryBean implements FactoryBean, ApplicationContextAware, NamedBean { + + public static final String FACTORY_BEAN_NAME = "httpResponseFactoryBean"; + + private ApplicationContext applicationContext; + + @Override + public HttpServletResponse getObject() throws Exception { + return applicationContext.getBean(FilterHttpResponse.class).getHttpServletReponse(); + } + + @Override + public Class getObjectType() { + return HttpServletResponse.class; + } + + @Override + public boolean isSingleton() { + return false; + } + + @Override + public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public String getBeanName() { + return FACTORY_BEAN_NAME; + } + +} diff --git a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/RequestResponseContextHolder.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/RequestResponseContextHolder.java new file mode 100644 index 000000000..f25a98810 --- /dev/null +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/RequestResponseContextHolder.java @@ -0,0 +1,43 @@ +/** + * 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.rest.util; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Store the request and response for the rest resources. + */ +public class RequestResponseContextHolder { + + private HttpServletRequest httpServletRequest; + + private HttpServletResponse httpServletResponse; + + public HttpServletRequest getHttpServletRequest() { + return httpServletRequest; + } + + public HttpServletResponse getHttpServletResponse() { + return httpServletResponse; + } + + @Autowired + public void setHttpServletRequest(final HttpServletRequest httpServletRequest) { + this.httpServletRequest = httpServletRequest; + } + + @Resource(name = HttpResponseFactoryBean.FACTORY_BEAN_NAME) + public void setHttpServletResponse(final HttpServletResponse httpServletResponse) { + this.httpServletResponse = httpServletResponse; + } +} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/helper/RestResourceConversionHelper.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/RestResourceConversionHelper.java similarity index 81% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/helper/RestResourceConversionHelper.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/RestResourceConversionHelper.java index e7b588222..0c9dd39c5 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/helper/RestResourceConversionHelper.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/RestResourceConversionHelper.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.helper; +package org.eclipse.hawkbit.rest.util; import static com.google.common.base.Preconditions.checkNotNull; @@ -22,11 +22,9 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; -import org.eclipse.hawkbit.cache.CacheWriteNotify; -import org.eclipse.hawkbit.controller.FileSteamingFailedException; -import org.eclipse.hawkbit.repository.model.Action.ActionType; +import org.eclipse.hawkbit.repository.ControllerManagement; +import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.LocalArtifact; -import org.eclipse.hawkbit.rest.resource.model.distributionset.ActionTypeRest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; @@ -39,9 +37,6 @@ import com.google.common.net.HttpHeaders; /** * Utility class for the Rest Source API. * - * - * - * */ public final class RestResourceConversionHelper { private static final Logger LOG = LoggerFactory.getLogger(RestResourceConversionHelper.class); @@ -67,7 +62,7 @@ public final class RestResourceConversionHelper { * * @return http code */ - public static ResponseEntity writeFileResponse(final LocalArtifact artifact, + public static ResponseEntity writeFileResponse(final LocalArtifact artifact, final HttpServletResponse servletResponse, final HttpServletRequest request, final DbArtifact file) { return writeFileResponse(artifact, servletResponse, request, file, null, null); } @@ -75,7 +70,7 @@ public final class RestResourceConversionHelper { /** *

* Write response with target relation and publishes events concerning the - * download progress based on given {@link UpdateActionStatus}. + * download progress based on given update action status. *

* *

@@ -90,23 +85,20 @@ public final class RestResourceConversionHelper { * from the client * @param file * to be write to the client response - * @param cacheWriteNotify + * @param controllerManagement * to write progress updates to * @param statusId - * of the UpdateActionStatus - * - * @throws IOException - * in case of exceptions + * of the {@link ActionStatus} * * @return http code * * @see https://tools.ietf.org/html/rfc7233 */ - public static ResponseEntity writeFileResponse(final LocalArtifact artifact, + public static ResponseEntity writeFileResponse(final LocalArtifact artifact, final HttpServletResponse response, final HttpServletRequest request, final DbArtifact file, - final CacheWriteNotify cacheWriteNotify, final Long statusId) { + final ControllerManagement controllerManagement, final Long statusId) { - ResponseEntity result = null; + ResponseEntity result; final String etag = artifact.getSha1Hash(); final Long lastModified = artifact.getLastModifiedAt() != null ? artifact.getLastModifiedAt() @@ -152,19 +144,19 @@ public final class RestResourceConversionHelper { // full request - no range if (ranges.isEmpty() || ranges.get(0).equals(full)) { LOG.debug("filename ({}) results into a full request: ", artifact.getFilename()); - fullfileRequest(artifact, response, file, cacheWriteNotify, statusId, full); + fullfileRequest(artifact, response, file, controllerManagement, statusId, full); result = new ResponseEntity<>(HttpStatus.OK); } // standard range request else if (ranges.size() == 1) { LOG.debug("filename ({}) results into a standard range request: ", artifact.getFilename()); - standardRangeRequest(artifact, response, file, cacheWriteNotify, statusId, ranges); + standardRangeRequest(artifact, response, file, controllerManagement, statusId, ranges); result = new ResponseEntity<>(HttpStatus.PARTIAL_CONTENT); } // multipart range request else { LOG.debug("filename ({}) results into a multipart range request: ", artifact.getFilename()); - multipartRangeRequest(artifact, response, file, cacheWriteNotify, statusId, ranges); + multipartRangeRequest(artifact, response, file, controllerManagement, statusId, ranges); result = new ResponseEntity<>(HttpStatus.PARTIAL_CONTENT); } @@ -173,23 +165,24 @@ public final class RestResourceConversionHelper { } private static void fullfileRequest(final LocalArtifact artifact, final HttpServletResponse response, - final DbArtifact file, final CacheWriteNotify cacheWriteNotify, final Long statusId, final ByteRange full) { + final DbArtifact file, final ControllerManagement controllerManagement, final Long statusId, + final ByteRange full) { final ByteRange r = full; response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + r.getStart() + "-" + r.getEnd() + "/" + r.getTotal()); response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(r.getLength())); try { - copyStreams(file.getFileInputStream(), response.getOutputStream(), cacheWriteNotify, statusId, r.getStart(), - r.getLength()); + copyStreams(file.getFileInputStream(), response.getOutputStream(), controllerManagement, statusId, + r.getStart(), r.getLength()); } catch (final IOException e) { LOG.error("fullfileRequest of file ({}) failed!", artifact.getFilename(), e); throw new FileSteamingFailedException(artifact.getFilename()); } } - private static ResponseEntity extractRange(final HttpServletResponse response, final long length, + private static ResponseEntity extractRange(final HttpServletResponse response, final long length, final List ranges, final String range) { - ResponseEntity result = null; + ResponseEntity result = null; if (ranges.isEmpty()) { for (final String part : range.substring(6).split(",")) { long start = sublong(part, 0, part.indexOf('-')); @@ -240,7 +233,7 @@ public final class RestResourceConversionHelper { } private static void multipartRangeRequest(final LocalArtifact artifact, final HttpServletResponse response, - final DbArtifact file, final CacheWriteNotify cacheWriteNotify, final Long statusId, + final DbArtifact file, final ControllerManagement controllerManagement, final Long statusId, final List ranges) { response.setContentType("multipart/byteranges; boundary=" + ByteRange.MULTIPART_BOUNDARY); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); @@ -254,7 +247,7 @@ public final class RestResourceConversionHelper { .println("Content-Range: bytes " + r.getStart() + "-" + r.getEnd() + "/" + r.getTotal()); // Copy single part range of multi part range. - copyStreams(file.getFileInputStream(), response.getOutputStream(), cacheWriteNotify, statusId, + copyStreams(file.getFileInputStream(), response.getOutputStream(), controllerManagement, statusId, r.getStart(), r.getLength()); } @@ -268,7 +261,7 @@ public final class RestResourceConversionHelper { } private static void standardRangeRequest(final LocalArtifact artifact, final HttpServletResponse response, - final DbArtifact file, final CacheWriteNotify cacheWriteNotify, final Long statusId, + final DbArtifact file, final ControllerManagement controllerManagement, final Long statusId, final List ranges) { final ByteRange r = ranges.get(0); response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + r.getStart() + "-" + r.getEnd() + "/" + r.getTotal()); @@ -276,8 +269,8 @@ public final class RestResourceConversionHelper { response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); try { - copyStreams(file.getFileInputStream(), response.getOutputStream(), cacheWriteNotify, statusId, r.getStart(), - r.getLength()); + copyStreams(file.getFileInputStream(), response.getOutputStream(), controllerManagement, statusId, + r.getStart(), r.getLength()); } catch (final IOException e) { LOG.error("standardRangeRequest of file ({}) failed!", artifact.getFilename(), e); throw new FileSteamingFailedException(artifact.getFilename()); @@ -285,8 +278,8 @@ public final class RestResourceConversionHelper { } private static long copyStreams(final InputStream from, final OutputStream to, - final CacheWriteNotify cacheWriteNotify, final Long statusId, final long start, final long length) - throws IOException { + final ControllerManagement controllerManagement, final Long statusId, final long start, final long length) + throws IOException { checkNotNull(from); checkNotNull(to); final byte[] buf = new byte[BUFFER_SIZE]; @@ -301,6 +294,7 @@ public final class RestResourceConversionHelper { long toRead = length; boolean toContinue = true; + long shippedSinceLastEvent = 0; while (toContinue) { final int r = from.read(buf); @@ -312,19 +306,22 @@ public final class RestResourceConversionHelper { if (toRead > 0) { to.write(buf, 0, r); total += r; + shippedSinceLastEvent += r; } else { to.write(buf, 0, (int) toRead + r); total += toRead + r; + shippedSinceLastEvent += toRead + r; toContinue = false; } - if (cacheWriteNotify != null) { + if (controllerManagement != null) { final int newPercent = DoubleMath.roundToInt(total * 100.0 / length, RoundingMode.DOWN); // every 10 percent an event if (newPercent == 100 || newPercent > progressPercent + 10) { progressPercent = newPercent; - cacheWriteNotify.downloadProgressPercent(statusId, progressPercent); + controllerManagement.downloadProgress(statusId, length, shippedSinceLastEvent, total); + shippedSinceLastEvent = 0; } } } @@ -347,28 +344,4 @@ public final class RestResourceConversionHelper { return Arrays.binarySearch(matchValues, toMatch) > -1 || Arrays.binarySearch(matchValues, "*") > -1; } - /** - * Convert a action rest type to a action repository type. - * - * @param actionTypeRest - * the rest type - * @return or the action repository type - */ - public static ActionType convertActionType(final ActionTypeRest actionTypeRest) { - if (actionTypeRest == null) { - return null; - } - - switch (actionTypeRest) { - case SOFT: - return ActionType.SOFT; - case FORCED: - return ActionType.FORCED; - case TIMEFORCED: - return ActionType.TIMEFORCED; - default: - throw new IllegalStateException("Action Type is not supported"); - } - - } } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortUtility.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/SortUtility.java similarity index 94% rename from hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortUtility.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/SortUtility.java index f8b997bf9..d0abc47a7 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SortUtility.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/SortUtility.java @@ -6,12 +6,15 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.rest.util; import java.util.List; import java.util.StringTokenizer; import org.eclipse.hawkbit.repository.FieldNameProvider; +import org.eclipse.hawkbit.rest.exception.SortParameterSyntaxErrorException; +import org.eclipse.hawkbit.rest.exception.SortParameterUnsupportedDirectionException; +import org.eclipse.hawkbit.rest.exception.SortParameterUnsupportedFieldException; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; diff --git a/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTest.java b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTest.java new file mode 100644 index 000000000..1708bf6cc --- /dev/null +++ b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTest.java @@ -0,0 +1,33 @@ +/** + * 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.rest; + +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest; +import org.eclipse.hawkbit.rest.configuration.RestConfiguration; +import org.eclipse.hawkbit.rest.util.FilterHttpResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; + +/** + * Abstract Test for Rest tests. + */ +@SpringApplicationConfiguration(classes = { RestConfiguration.class, + org.eclipse.hawkbit.RepositoryApplicationConfiguration.class }) +public abstract class AbstractRestIntegrationTest extends AbstractIntegrationTest { + + @Autowired + private FilterHttpResponse filterHttpResponse; + + @Override + protected DefaultMockMvcBuilder createMvcWebAppContext() { + final DefaultMockMvcBuilder createMvcWebAppContext = super.createMvcWebAppContext(); + return createMvcWebAppContext.addFilter(filterHttpResponse); + } +} diff --git a/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTestWithMongoDB.java b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTestWithMongoDB.java new file mode 100644 index 000000000..70d65e141 --- /dev/null +++ b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTestWithMongoDB.java @@ -0,0 +1,33 @@ +/** + * 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.rest; + +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB; +import org.eclipse.hawkbit.rest.configuration.RestConfiguration; +import org.eclipse.hawkbit.rest.util.FilterHttpResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; + +/** + * Abstract Test for Rest tests. + */ +@SpringApplicationConfiguration(classes = { RestConfiguration.class, + org.eclipse.hawkbit.RepositoryApplicationConfiguration.class }) +public abstract class AbstractRestIntegrationTestWithMongoDB extends AbstractIntegrationTestWithMongoDB { + + @Autowired + private FilterHttpResponse filterHttpResponse; + + @Override + protected DefaultMockMvcBuilder createMvcWebAppContext() { + final DefaultMockMvcBuilder createMvcWebAppContext = super.createMvcWebAppContext(); + return createMvcWebAppContext.addFilter(filterHttpResponse); + } +} diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/model/ExceptionInfoTest.java b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/json/model/ExceptionInfoTest.java similarity index 97% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/model/ExceptionInfoTest.java rename to hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/json/model/ExceptionInfoTest.java index d240a814b..901702795 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/model/ExceptionInfoTest.java +++ b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/json/model/ExceptionInfoTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource.model; +package org.eclipse.hawkbit.rest.json.model; import static org.fest.assertions.Assertions.assertThat; diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/JsonBuilder.java b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/JsonBuilder.java similarity index 93% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/JsonBuilder.java rename to hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/JsonBuilder.java index dec0bb070..0ee2c846d 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/JsonBuilder.java +++ b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/JsonBuilder.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.rest.util; import java.util.ArrayList; import java.util.List; @@ -16,7 +16,7 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.RandomStringUtils; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupConditions; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.Target; @@ -41,9 +41,9 @@ public abstract class JsonBuilder { try { builder.append(new JSONObject().put("name", module.getName()) .put("description", module.getDescription()).put("type", module.getType().getKey()) - .put("id", Long.MAX_VALUE).put("vendor", module.getVendor()) - .put("version", module.getVersion()).put("createdAt", "0").put("updatedAt", "0") - .put("createdBy", "fghdfkjghdfkjh").put("updatedBy", "fghdfkjghdfkjh").toString()); + .put("id", Long.MAX_VALUE).put("vendor", module.getVendor()).put("version", module.getVersion()) + .put("createdAt", "0").put("updatedAt", "0").put("createdBy", "fghdfkjghdfkjh") + .put("updatedBy", "fghdfkjghdfkjh").toString()); } catch (final Exception e) { e.printStackTrace(); } @@ -185,15 +185,13 @@ public abstract class JsonBuilder { final List messages = new ArrayList(); messages.add(message); - return new JSONObject() - .put("id", id) - .put("time", "20140511T121314") + return new JSONObject().put("id", id).put("time", "20140511T121314") .put("status", - new JSONObject() - .put("execution", execution) + new JSONObject().put("execution", execution) .put("result", new JSONObject().put("finished", finished).put("progress", - new JSONObject().put("cnt", 2).put("of", 5))).put("details", messages)) + new JSONObject().put("cnt", 2).put("of", 5))) + .put("details", messages)) .toString(); } @@ -369,21 +367,22 @@ public abstract class JsonBuilder { } - /** - * @param targets - * @return - */ - public static String targets(final List targets) { + public static String targets(final List targets, final boolean withToken) { final StringBuilder builder = new StringBuilder(); builder.append("["); int i = 0; for (final Target target : targets) { try { + final String address = target.getTargetInfo().getAddress() != null + ? target.getTargetInfo().getAddress().toString() : null; + + final String token = withToken ? target.getSecurityToken() : null; + builder.append(new JSONObject().put("controllerId", target.getControllerId()) - .put("description", target.getDescription()).put("name", target.getName()) - .put("createdAt", "0").put("updatedAt", "0").put("createdBy", "fghdfkjghdfkjh") - .put("updatedBy", "fghdfkjghdfkjh").toString()); + .put("description", target.getDescription()).put("name", target.getName()).put("createdAt", "0") + .put("updatedAt", "0").put("createdBy", "fghdfkjghdfkjh").put("updatedBy", "fghdfkjghdfkjh") + .put("address", address).put("securityToken", token).toString()); } catch (final Exception e) { e.printStackTrace(); } @@ -441,9 +440,7 @@ public abstract class JsonBuilder { throws JSONException { final List messages = new ArrayList(); messages.add(message); - return new JSONObject() - .put("id", id) - .put("time", "20140511T121314") + return new JSONObject().put("id", id).put("time", "20140511T121314") .put("status", new JSONObject().put("execution", execution) .put("result", new JSONObject().put("finished", "success")).put("details", messages)) @@ -453,13 +450,12 @@ public abstract class JsonBuilder { public static String configData(final String id, final Map attributes, final String execution) throws JSONException { - return new JSONObject() - .put("id", id) - .put("time", "20140511T121314") + return new JSONObject().put("id", id).put("time", "20140511T121314") .put("status", new JSONObject().put("execution", execution) .put("result", new JSONObject().put("finished", "success")) - .put("details", new ArrayList())).put("data", attributes).toString(); + .put("details", new ArrayList())) + .put("data", attributes).toString(); } diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/MockMvcResultPrinter.java b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/MockMvcResultPrinter.java similarity index 97% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/MockMvcResultPrinter.java rename to hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/MockMvcResultPrinter.java index b01bb4e9f..b1de56f61 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/MockMvcResultPrinter.java +++ b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/MockMvcResultPrinter.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit; +package org.eclipse.hawkbit.rest.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SortUtilityTest.java b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/SortUtilityTest.java similarity index 91% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SortUtilityTest.java rename to hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/SortUtilityTest.java index 09a90c39c..8f1b814bf 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SortUtilityTest.java +++ b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/SortUtilityTest.java @@ -6,14 +6,17 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.rest.util; -import static org.fest.assertions.api.Assertions.assertThat; +import static org.fest.assertions.Assertions.assertThat; import static org.junit.Assert.fail; import java.util.List; import org.eclipse.hawkbit.repository.TargetFields; +import org.eclipse.hawkbit.rest.exception.SortParameterSyntaxErrorException; +import org.eclipse.hawkbit.rest.exception.SortParameterUnsupportedDirectionException; +import org.eclipse.hawkbit.rest.exception.SortParameterUnsupportedFieldException; import org.junit.Test; import org.springframework.data.domain.Sort.Order; diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SuccessCondition.java b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/SuccessCondition.java similarity index 92% rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SuccessCondition.java rename to hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/SuccessCondition.java index be6e166ef..f3424b0c0 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SuccessCondition.java +++ b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/util/SuccessCondition.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.rest.resource; +package org.eclipse.hawkbit.rest.util; /** * 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 deleted file mode 100644 index a36443024..000000000 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ArtifactStoreController.java +++ /dev/null @@ -1,190 +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.controller; - -import java.io.IOException; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; -import org.eclipse.hawkbit.cache.CacheWriteNotify; -import org.eclipse.hawkbit.repository.ArtifactManagement; -import org.eclipse.hawkbit.repository.ControllerManagement; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.repository.model.ActionStatus; -import org.eclipse.hawkbit.repository.model.Artifact; -import org.eclipse.hawkbit.repository.model.LocalArtifact; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper; -import org.eclipse.hawkbit.security.HawkbitSecurityProperties; -import org.eclipse.hawkbit.util.IpUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.web.bind.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -/** - * The {@link ArtifactStoreController} of the SP server controller API that is - * queried by the SP target in order to download artifacts independent of their - * own individual resource. This is offered in addition to the - * {@link RootController#downloadArtifact(String, Long, Long, javax.servlet.http.HttpServletResponse)} - * for legacy controllers that can not be fed with a download URI at runtime. - * - * - * - * - * - */ -@RestController -@RequestMapping(ControllerConstants.ARTIFACTS_V1_REQUEST_MAPPING) -public class ArtifactStoreController { - private static final Logger LOG = LoggerFactory.getLogger(ArtifactStoreController.class); - - @Autowired - private ArtifactManagement artifactManagement; - - @Autowired - private ControllerManagement controllerManagement; - - @Autowired - private CacheWriteNotify cacheWriteNotify; - - @Autowired - private HawkbitSecurityProperties securityProperties; - - /** - * Handles GET {@link Artifact} download request. This could be full or - * partial download request. - * - * @param fileName - * to search for - * @param response - * to write to - * @param request - * from the client - * @param targetid - * of authenticated target - * - * @return response of the servlet which in case of success is status code - * {@link HttpStatus#OK} or in case of partial download - * {@link HttpStatus#PARTIAL_CONTENT}. - */ - @RequestMapping(method = RequestMethod.GET, value = ControllerConstants.ARTIFACT_DOWNLOAD_BY_FILENAME - + "/{fileName}") - @ResponseBody - public ResponseEntity downloadArtifactByFilename(@PathVariable final String fileName, - final HttpServletResponse response, final HttpServletRequest request, - @AuthenticationPrincipal final String targetid) { - ResponseEntity result; - - final List foundArtifacts = artifactManagement.findLocalArtifactByFilename(fileName); - - if (foundArtifacts.isEmpty()) { - LOG.warn("Software artifact with name {} could not be found.", fileName); - result = new ResponseEntity<>(HttpStatus.NOT_FOUND); - } else { - if (foundArtifacts.size() > 1) { - LOG.warn("Software artifact name {} is not unique. We will use the first entry.", fileName); - } - - final LocalArtifact artifact = foundArtifacts.get(0); - - final String ifMatch = request.getHeader("If-Match"); - if (ifMatch != null && !RestResourceConversionHelper.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) { - result = new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED); - } else { - final DbArtifact file = artifactManagement.loadLocalArtifactBinary(artifact); - - // we set a download status only if we are aware of the - // targetid, i.e. - // authenticated and not anonymous - if (targetid != null && !"anonymous".equals(targetid)) { - final Action action = checkAndReportDownloadByTarget(request, targetid, artifact); - result = RestResourceConversionHelper.writeFileResponse(artifact, response, request, file, - cacheWriteNotify, action.getId()); - } else { - result = RestResourceConversionHelper.writeFileResponse(artifact, response, request, file); - } - - } - } - - return result; - } - - private Action checkAndReportDownloadByTarget(final HttpServletRequest request, final String targetid, - final LocalArtifact artifact) { - final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader())); - - final Action action = controllerManagement - .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), artifact.getSoftwareModule()); - final String range = request.getHeader("Range"); - - final ActionStatus actionStatus = new ActionStatus(); - actionStatus.setAction(action); - actionStatus.setOccurredAt(System.currentTimeMillis()); - actionStatus.setStatus(Status.DOWNLOAD); - - if (range != null) { - actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads range " + range - + " of: " + request.getRequestURI()); - } else { - actionStatus.addMessage( - ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads: " + request.getRequestURI()); - } - controllerManagement.addActionStatusMessage(actionStatus); - return action; - } - - /** - * Handles GET {@link Artifact} MD5 checksum file download request. - * - * @param fileName - * to search for - * @param response - * to write to - * - * @return response of the servlet - */ - @RequestMapping(method = RequestMethod.GET, value = ControllerConstants.ARTIFACT_DOWNLOAD_BY_FILENAME - + "/{fileName}" + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX) - @ResponseBody - public ResponseEntity downloadArtifactMD5ByFilename(@PathVariable final String fileName, - final HttpServletResponse response) { - final List foundArtifacts = artifactManagement.findLocalArtifactByFilename(fileName); - - if (foundArtifacts.isEmpty()) { - LOG.warn("Softeare artifact with name {} could not be found.", fileName); - return new ResponseEntity<>(HttpStatus.NOT_FOUND); - } else if (foundArtifacts.size() > 1) { - LOG.error("Softeare artifact name {} is not unique.", fileName); - } - - try { - DataConversionHelper.writeMD5FileResponse(fileName, response, foundArtifacts.get(0)); - } catch (final IOException e) { - LOG.error("Failed to stream MD5 File", e); - return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); - } - - return new ResponseEntity<>(HttpStatus.OK); - } - -} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/ControllerBase.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/ControllerBase.java deleted file mode 100644 index d319bcf11..000000000 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/model/ControllerBase.java +++ /dev/null @@ -1,39 +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.controller.model; - -import org.springframework.hateoas.ResourceSupport; - -/** - * {@link ControllerBase} resource content. - * - */ -public class ControllerBase extends ResourceSupport { - - private final Config config; - - /** - * Constructor. - * - * @param config - * configuration of the SP target - */ - public ControllerBase(final Config config) { - super(); - this.config = config; - } - - /** - * @return the config - */ - public Config getConfig() { - return config; - } - -} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/OffsetBasedPageRequest.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/OffsetBasedPageRequest.java deleted file mode 100644 index 5ab6b33c6..000000000 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/OffsetBasedPageRequest.java +++ /dev/null @@ -1,69 +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.rest.resource; - -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; - -/** - * An implementation of the {@link PageRequest} which is offset based by means - * the offset is given and not the page number as in the original - * {@link PageRequest} implemntation where the offset is generated. Due that the - * REST-API is working with {@code offset} and {@code limit} parameter we need - * an offset based page request for JPA. - * - * - * - * - */ -public final class OffsetBasedPageRequest extends PageRequest { - - private static final long serialVersionUID = 1L; - private final int offset; - - /** - * Creates a new {@link OffsetBasedPageRequest}. Offsets are zero indexed, - * thus providing 0 for {@code offset} will return the first entry. - * - * @param offset - * zero-based offset index. - * @param limit - * the limit of the page to be returned. - */ - public OffsetBasedPageRequest(final int offset, final int limit) { - this(offset, limit, null); - } - - /** - * Creates a new {@link OffsetBasedPageRequest}. Offsets are zero indexed, - * thus providing 0 for {@code offset} will return the first entry. - * - * @param offset - * zero-based offset index. - * @param limit - * the limit of the page to be returned. - * @param sort - * sort can be {@literal null}. - */ - public OffsetBasedPageRequest(final int offset, final int limit, final Sort sort) { - super(0, limit, sort); - this.offset = offset; - } - - @Override - public int getOffset() { - return offset; - } - - @Override - public String toString() { - return "OffsetBasedPageRequest [offset=" + offset + ", getPageSize()=" + getPageSize() + ", getPageNumber()=" - + getPageNumber() + "]"; - } -} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RestModelMapper.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RestModelMapper.java deleted file mode 100644 index 9616d0e86..000000000 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RestModelMapper.java +++ /dev/null @@ -1,48 +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.rest.resource; - -import org.eclipse.hawkbit.repository.model.NamedEntity; -import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; -import org.eclipse.hawkbit.rest.resource.model.BaseEntityRest; -import org.eclipse.hawkbit.rest.resource.model.NamedEntityRest; - -/** - * A mapper which maps repository model to RESTful model representation and - * back. - * - * - * - * - */ -final class RestModelMapper { - - // private constructor, utility class - private RestModelMapper() { - - } - - static void mapBaseToBase(final BaseEntityRest response, final TenantAwareBaseEntity base) { - response.setCreatedBy(base.getCreatedBy()); - response.setLastModifiedBy(base.getLastModifiedBy()); - if (base.getCreatedAt() != null) { - response.setCreatedAt(base.getCreatedAt()); - } - if (base.getLastModifiedAt() != null) { - response.setLastModifiedAt(base.getLastModifiedAt()); - } - } - - static void mapNamedToNamed(final NamedEntityRest response, final NamedEntity base) { - mapBaseToBase(response, base); - - response.setName(base.getName()); - response.setDescription(base.getDescription()); - } -} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleMapper.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleMapper.java deleted file mode 100644 index 01dfae9cd..000000000 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleMapper.java +++ /dev/null @@ -1,201 +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.rest.resource; - -import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; -import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.hawkbit.repository.SoftwareManagement; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.model.Artifact; -import org.eclipse.hawkbit.repository.model.LocalArtifact; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleRestAPI; -import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleTypeRestApi; -import org.eclipse.hawkbit.rest.resource.model.MetadataRest; -import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactHash; -import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactRest; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRest; - -/** - * A mapper which maps repository model to RESTful model representation and - * back. - * - */ -public final class SoftwareModuleMapper { - private SoftwareModuleMapper() { - // Utility class - } - - private static SoftwareModuleType getSoftwareModuleTypeFromKeyString(final String type, - final SoftwareManagement softwareManagement) { - - final SoftwareModuleType smType = softwareManagement.findSoftwareModuleTypeByKey(type.trim()); - - if (smType == null) { - throw new EntityNotFoundException(type.trim()); - } - - return smType; - } - - static SoftwareModule fromRequest(final SoftwareModuleRequestBodyPost smsRest, - final SoftwareManagement softwareManagement) { - return new SoftwareModule(getSoftwareModuleTypeFromKeyString(smsRest.getType(), softwareManagement), - smsRest.getName(), smsRest.getVersion(), smsRest.getDescription(), smsRest.getVendor()); - } - - static List fromRequestSwMetadata(final SoftwareModule sw, - final List metadata) { - final List mappedList = new ArrayList<>(metadata.size()); - for (final MetadataRest metadataRest : metadata) { - if (metadataRest.getKey() == null) { - throw new IllegalArgumentException("the key of the metadata must be present"); - } - mappedList.add(new SoftwareModuleMetadata(metadataRest.getKey(), sw, metadataRest.getValue())); - } - return mappedList; - } - - static List smFromRequest(final Iterable smsRest, - final SoftwareManagement softwareManagement) { - final List mappedList = new ArrayList<>(); - for (final SoftwareModuleRequestBodyPost smRest : smsRest) { - mappedList.add(fromRequest(smRest, softwareManagement)); - } - return mappedList; - } - - /** - * Create response for sw modules. - * - * @param baseSoftareModules - * the modules - * @return the response - */ - public static List toResponse(final List baseSoftareModules) { - final List mappedList = new ArrayList<>(); - if (baseSoftareModules != null) { - for (final SoftwareModule target : baseSoftareModules) { - final SoftwareModuleRest response = toResponse(target); - - mappedList.add(response); - } - } - return mappedList; - } - - static List toResponseSoftwareModules(final Iterable softwareModules) { - final List response = new ArrayList<>(); - for (final SoftwareModule softwareModule : softwareModules) { - response.add(toResponse(softwareModule)); - } - return response; - } - - static List toResponseSwMetadata(final List metadata) { - final List mappedList = new ArrayList<>(metadata.size()); - for (final SoftwareModuleMetadata distributionSetMetadata : metadata) { - mappedList.add(toResponseSwMetadata(distributionSetMetadata)); - } - return mappedList; - } - - static MetadataRest toResponseSwMetadata(final SoftwareModuleMetadata metadata) { - final MetadataRest metadataRest = new MetadataRest(); - metadataRest.setKey(metadata.getId().getKey()); - metadataRest.setValue(metadata.getValue()); - return metadataRest; - } - - /** - * Create response for one sw module. - * - * @param baseSofwareModule - * the sw module - * @return the response - */ - public static SoftwareModuleRest toResponse(final SoftwareModule baseSofwareModule) { - if (baseSofwareModule == null) { - return null; - } - - final SoftwareModuleRest response = new SoftwareModuleRest(); - RestModelMapper.mapNamedToNamed(response, baseSofwareModule); - response.setModuleId(baseSofwareModule.getId()); - response.setVersion(baseSofwareModule.getVersion()); - response.setType(baseSofwareModule.getType().getKey()); - response.setVendor(baseSofwareModule.getVendor()); - - response.add(linkTo(methodOn(SoftwareModuleRestAPI.class).getArtifacts(response.getModuleId())) - .withRel(RestConstants.SOFTWAREMODULE_V1_ARTIFACT)); - response.add(linkTo(methodOn(SoftwareModuleRestAPI.class).getSoftwareModule(response.getModuleId())) - .withRel("self")); - - response.add(linkTo( - methodOn(SoftwareModuleTypeRestApi.class).getSoftwareModuleType(baseSofwareModule.getType().getId())) - .withRel(RestConstants.SOFTWAREMODULE_V1_TYPE)); - - response.add(linkTo(methodOn(SoftwareModuleResource.class).getMetadata(response.getModuleId(), - Integer.parseInt(RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET), - Integer.parseInt(RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT), null, null)) - .withRel("metadata")); - return response; - } - - /** - * @param artifact - * @return - */ - static ArtifactRest toResponse(final Artifact artifact) { - final ArtifactRest.ArtifactType type = artifact instanceof LocalArtifact ? ArtifactRest.ArtifactType.LOCAL - : ArtifactRest.ArtifactType.EXTERNAL; - - final ArtifactRest artifactRest = new ArtifactRest(); - artifactRest.setType(type); - artifactRest.setArtifactId(artifact.getId()); - artifactRest.setSize(artifact.getSize()); - artifactRest.setHashes(new ArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash())); - - if (artifact instanceof LocalArtifact) { - artifactRest.setProvidedFilename(((LocalArtifact) artifact).getFilename()); - } - - RestModelMapper.mapBaseToBase(artifactRest, artifact); - - artifactRest.add(linkTo(methodOn(SoftwareModuleRestAPI.class).getArtifact(artifact.getSoftwareModule().getId(), - artifact.getId())).withRel("self")); - - if (artifact instanceof LocalArtifact) { - artifactRest.add(linkTo(methodOn(DownloadArtifactResource.class) - .downloadArtifact(artifact.getSoftwareModule().getId(), artifact.getId(), null, null)) - .withRel("download")); - } - - return artifactRest; - } - - static List artifactsToResponse(final List artifacts) { - final List mappedList = new ArrayList<>(); - - if (artifacts != null) { - for (final Artifact artifact : artifacts) { - final ArtifactRest response = toResponse(artifact); - mappedList.add(response); - } - } - return mappedList; - } -} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeMapper.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeMapper.java deleted file mode 100644 index b6525948c..000000000 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeMapper.java +++ /dev/null @@ -1,82 +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.rest.resource; - -import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; -import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleTypeRestApi; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRest; - -/** - * A mapper which maps repository model to RESTful model representation and - * back. - * - * - * - * - */ -final class SoftwareModuleTypeMapper { - - // private constructor, utility class - private SoftwareModuleTypeMapper() { - - } - - static List smFromRequest(final Iterable smTypesRest) { - final List mappedList = new ArrayList<>(); - - for (final SoftwareModuleTypeRequestBodyPost smRest : smTypesRest) { - mappedList.add(fromRequest(smRest)); - } - return mappedList; - } - - static SoftwareModuleType fromRequest(final SoftwareModuleTypeRequestBodyPost smsRest) { - return new SoftwareModuleType(smsRest.getKey(), smsRest.getName(), smsRest.getDescription(), - smsRest.getMaxAssignments()); - } - - static List toTypesResponse(final List types) { - final List response = new ArrayList<>(); - for (final SoftwareModuleType softwareModule : types) { - response.add(toResponse(softwareModule)); - } - return response; - } - - static List toListResponse(final Collection types) { - final List response = new ArrayList<>(); - for (final SoftwareModuleType softwareModule : types) { - response.add(toResponse(softwareModule)); - } - return response; - } - - static SoftwareModuleTypeRest toResponse(final SoftwareModuleType type) { - final SoftwareModuleTypeRest result = new SoftwareModuleTypeRest(); - - RestModelMapper.mapNamedToNamed(result, type); - result.setKey(type.getKey()); - result.setMaxAssignments(type.getMaxAssignments()); - result.setModuleId(type.getId()); - - result.add(linkTo(methodOn(SoftwareModuleTypeRestApi.class).getSoftwareModuleType(result.getModuleId())) - .withRel("self")); - - return result; - } - -} diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/ConfigurationResourceTest.java b/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/ConfigurationResourceTest.java deleted file mode 100644 index 39e571a2c..000000000 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/ConfigurationResourceTest.java +++ /dev/null @@ -1,146 +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.rest.resource; - -import static org.fest.assertions.api.Assertions.assertThat; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.Matchers.hasSize; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import org.eclipse.hawkbit.AbstractIntegrationTest; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.exception.SpServerError; -import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.rest.resource.model.ExceptionInfo; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; -import org.junit.Test; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.ResultActions; - -import ru.yandex.qatools.allure.annotations.Description; -import ru.yandex.qatools.allure.annotations.Features; -import ru.yandex.qatools.allure.annotations.Stories; - -@Features("Component Tests - Management RESTful API") -@Stories("ConfigurationResource") -public class ConfigurationResourceTest extends AbstractIntegrationTest { - - private static String BASE_JSON_REQUEST_STRING = "{\"value\":\"%s\"}"; - - @Test - @Description("perform a GET request on all existing configurations.") - public void getConfigurationValues() throws Exception { - - final ResultActions resultActions = mvc.perform(get(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/")) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) - .andExpect(jsonPath("$.*", hasSize(TenantConfigurationKey.values().length))); - - for (final TenantConfigurationKey key : TenantConfigurationKey.values()) { - - final TenantConfigurationValue confValue = tenantConfigurationManagement.getConfigurationValue(key); - resultActions.andExpect(jsonPath("$.['" + key.getKeyName() + "'].value", equalTo(confValue.getValue()))) - .andExpect(jsonPath("$.['" + key.getKeyName() + "'].global", equalTo(confValue.isGlobal()))); - } - } - - @Test - @Description("perform a GET request on a existing configuration key.") - public void getConfigurationValue() throws Exception { - - final TenantConfigurationKey key = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME; - final String notGlobalValue = "notTheGlobalHeaderAuthoryName"; - - tenantConfigurationManagement.addOrUpdateConfiguration(key, notGlobalValue); - - mvc.perform(get(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}/", key.getKeyName())) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) - .andExpect(jsonPath("value", equalTo(notGlobalValue))).andExpect(jsonPath("global", equalTo(false))) - .andExpect(jsonPath("createdAt", notNullValue())).andExpect(jsonPath("createdBy", notNullValue())); - } - - @Test - @Description("perform a PUT request on a existing configuration key with a valid value.") - public void putConfigurationValue() throws Exception { - - final TenantConfigurationKey key = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME; - final String testValue = "12:12:12"; - - mvc.perform(put(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}/", key.getKeyName()) - .content(String.format(BASE_JSON_REQUEST_STRING, testValue)).contentType(MediaType.APPLICATION_JSON)) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); - - assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).getValue()) - .isEqualTo(testValue); - } - - @Test - @Description("perform a DELETE request on a existing configuration key.") - public void deleteConfigurationValue() throws Exception { - - final TenantConfigurationKey key = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME; - final String notGlobalValue = "notTheGlobalHeaderAuthoryName"; - - tenantConfigurationManagement.addOrUpdateConfiguration(key, notGlobalValue); - assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).isGlobal()).isEqualTo(false); - - assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).getValue()) - .isEqualTo(notGlobalValue); - - mvc.perform(delete(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}/", key.getKeyName())) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isNoContent()); - - assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).isGlobal()).isEqualTo(true); - assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).getValue()) - .isNotEqualTo(notGlobalValue); - } - - @Test - @Description("perform a (put) request on a not existing configuration key.") - public void putInvalidConfigurationKey() throws Exception { - - final String notExistingKey = "notExistingKey"; - final String testValue = "12:12:12"; - - final MvcResult mvcResult = mvc - .perform(put(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}", notExistingKey) - .content(String.format(BASE_JSON_REQUEST_STRING, testValue)) - .contentType(MediaType.APPLICATION_JSON)) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()).andReturn(); - - // verify response json exception message - final ExceptionInfo exceptionInfo = ResourceUtility - .convertException(mvcResult.getResponse().getContentAsString()); - assertThat(exceptionInfo.getErrorCode()).isEqualTo(SpServerError.SP_CONFIGURATION_KEY_INVALID.getKey()); - } - - @Test - @Description("perform a put request with a not matching configuration value.") - public void putInvalidConfigurationValue() throws Exception { - - final TenantConfigurationKey key = TenantConfigurationKey.POLLING_TIME_INTERVAL; - final String testValue = "invalidFormattedDuration"; - - final MvcResult mvcResult = mvc - .perform(put(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}", key.getKeyName()) - .content(String.format(BASE_JSON_REQUEST_STRING, testValue)) - .contentType(MediaType.APPLICATION_JSON)) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()).andReturn(); - - // verify response json exception message - final ExceptionInfo exceptionInfo = ResourceUtility - .convertException(mvcResult.getResponse().getContentAsString()); - assertThat(exceptionInfo.getErrorCode()).isEqualTo(SpServerError.SP_CONFIGURATION_VALUE_INVALID.getKey()); - } -} diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SystemManagementResourceTest.java b/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SystemManagementResourceTest.java deleted file mode 100644 index 76cd68d64..000000000 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SystemManagementResourceTest.java +++ /dev/null @@ -1,175 +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.rest.resource; - -import static org.fest.assertions.api.Assertions.assertThat; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.io.ByteArrayInputStream; -import java.util.List; -import java.util.Random; - -import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; -import org.eclipse.hawkbit.MockMvcResultPrinter; -import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.WithSpringAuthorityRule; -import org.eclipse.hawkbit.WithUser; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.Target; -import org.junit.Test; -import org.springframework.http.MediaType; - -import ru.yandex.qatools.allure.annotations.Description; -import ru.yandex.qatools.allure.annotations.Features; -import ru.yandex.qatools.allure.annotations.Stories; - -/** - * - * - */ -@Features("Component Tests - Management API") -@Stories("System Management Resource") -public class SystemManagementResourceTest extends AbstractIntegrationTestWithMongoDB { - - @Test - @WithUser(tenantId = "mytenant", authorities = { SpPermission.SYSTEM_ADMIN }) - @Description("Tests that the system is able to collect statistics for the entire system.") - public void collectSystemStatistics() throws Exception { - createTestTenantsForSystemStatistics(2, 2000, 100, 2); - - mvc.perform(get("/system/admin/usage").accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$tenantStats.[?(@.tenantName==tenant0)][0].targets", equalTo(100))) - .andExpect(jsonPath("$tenantStats.[?(@.tenantName==tenant0)][0].overallArtifactVolumeInBytes", - equalTo(2000))) - .andExpect(jsonPath("$tenantStats.[?(@.tenantName==tenant0)][0].artifacts", equalTo(1))) - .andExpect(jsonPath("$tenantStats.[?(@.tenantName==tenant0)][0].actions", equalTo(200))) - .andExpect(jsonPath("$overallTargets", equalTo(200))) - .andExpect(jsonPath("$overallArtifacts", equalTo(2))) - .andExpect(jsonPath("$overallArtifactVolumeInBytes", equalTo(4000))) - .andExpect(jsonPath("$overallActions", equalTo(400))) - .andExpect(jsonPath("$overallTenants", equalTo(4))); - } - - @Test - @WithUser(tenantId = "mytenant", authorities = { SpPermission.DELETE_TARGET, SpPermission.DELETE_REPOSITORY, - SpPermission.CREATE_REPOSITORY, SpPermission.READ_REPOSITORY }) - @Description("Tests that the system is not able to collect statistics for the entire system if the .") - public void collectSystemStatisticsWithMissingPermissionFails() throws Exception { - - mvc.perform(get("/system/admin/usage").accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isForbidden()); - } - - @Test - @WithUser(tenantId = "mytenant", allSpPermissions = true) - @Description("Tests that a tenant can be deletd by API.") - public void deleteTenant() throws Exception { - - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); - - assertThat(distributionSetManagement.findDistributionSetById(dsA.getId())).isNotNull(); - - mvc.perform(delete("/system/admin/tenants/mytenant")).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isOk()); - - assertThat(distributionSetManagement.findDistributionSetById(dsA.getId())).isNull(); - - } - - @Test - @WithUser(tenantId = "mytenant", authorities = { SpPermission.DELETE_TARGET, SpPermission.DELETE_REPOSITORY, - SpPermission.CREATE_REPOSITORY, SpPermission.READ_REPOSITORY }) - @Description("Tenant deletion is only possible for SYSTEM_ADMINs. Repository or target delete is not sufficient.") - public void deleteTenantFailsMissingPermission() throws Exception { - - final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, - distributionSetManagement); - assertThat(distributionSetManagement.findDistributionSetById(dsA.getId())).isNotNull(); - - mvc.perform(delete("/system/admin/tenants/mytenant")).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isForbidden()); - - assertThat(distributionSetManagement.findDistributionSetById(dsA.getId())).isNotNull(); - } - - @Test - public void getCachesReturnStatus200() throws Exception { - mvc.perform(get("/system/admin/caches")).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); - } - - @Test - public void invalidateCachesReturnStatus200() throws Exception { - mvc.perform(delete("/system/admin/caches")).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); - } - - private byte[] createTestTenantsForSystemStatistics(final int tenants, final int artifactSize, final int targets, - final int updates) throws Exception { - final Random randomgen = new Random(); - final byte random[] = new byte[artifactSize]; - randomgen.nextBytes(random); - - for (int i = 0; i < tenants; i++) { - final String tenantname = "tenant" + i; - securityRule.runAs(WithSpringAuthorityRule.withUserAndTenant("bumlux", tenantname), () -> { - systemManagement.getTenantMetadata(tenantname); - if (artifactSize > 0) { - createTestArtifact(random); - createDeletedTestArtifact(random); - } - if (targets > 0) { - final List createdTargets = createTestTargets(targets); - if (updates > 0) { - for (int x = 0; x < updates; x++) { - final DistributionSet ds = TestDataUtil.generateDistributionSet("to be deployed" + x, - softwareManagement, distributionSetManagement, true); - - deploymentManagement.assignDistributionSet(ds, createdTargets); - } - } - } - - return null; - }); - } - - return random; - } - - private List createTestTargets(final int targets) { - return targetManagement - .createTargets(TestDataUtil.buildTargetFixtures(targets, "testTargetOfTenant", "testTargetOfTenant")); - } - - private void createTestArtifact(final byte[] random) { - SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1", - "version 1", null, null); - sm = softwareModuleRepository.save(sm); - - artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), sm.getId(), "file1", false); - } - - private void createDeletedTestArtifact(final byte[] random) { - final DistributionSet ds = TestDataUtil.generateDistributionSet("deleted garbage", softwareManagement, - distributionSetManagement, true); - ds.getModules().stream().forEach(module -> { - artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), module.getId(), "file1", false); - softwareManagement.deleteSoftwareModule(module); - }); - } - -} diff --git a/hawkbit-rest-resource/src/test/resources/log4j2.xml b/hawkbit-rest-resource/src/test/resources/log4j2.xml deleted file mode 100644 index 98ea99ac9..000000000 --- a/hawkbit-rest-resource/src/test/resources/log4j2.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/hawkbit-security-core/pom.xml b/hawkbit-security-core/pom.xml index a3b262726..a9b2347b6 100644 --- a/hawkbit-security-core/pom.xml +++ b/hawkbit-security-core/pom.xml @@ -21,7 +21,7 @@ - + org.eclipse.hawkbit hawkbit-core ${project.version} diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionService.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionService.java index bad24e6c4..2cbadd02d 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionService.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionService.java @@ -17,7 +17,7 @@ import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; /** - * + * Service to check permissions. * */ public class PermissionService { diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionUtils.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionUtils.java new file mode 100644 index 000000000..98cde9642 --- /dev/null +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionUtils.java @@ -0,0 +1,55 @@ +/** + * 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.im.authentication; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +/** + * Utility method for creation of GrantedAuthority collections etc. + */ +public final class PermissionUtils { + + private PermissionUtils() { + + } + + /** + * Create {@link GrantedAuthority} by a special role. + * + * @param roles + * the roles + * @return a list of {@link GrantedAuthority} + */ + public static List createAuthorityList(final Collection roles) { + final List authorities = new ArrayList<>(roles.size()); + + for (final String role : roles) { + authorities.add(new SimpleGrantedAuthority(role)); + // add spring security ROLE authority which is indicated by the + // `ROLE_` prefix + authorities.add(new SimpleGrantedAuthority("ROLE_" + role)); + } + + return authorities; + } + + /** + * Returns all authorities. + * + * @return a list of {@link GrantedAuthority} + */ + public static List createAllAuthorityList() { + return createAuthorityList(SpPermission.getAllAuthorities()); + } +} diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java index 2e222d879..daf5f0dd9 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java @@ -9,7 +9,16 @@ package org.eclipse.hawkbit.im.authentication; import java.lang.annotation.Target; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.GrantedAuthority; @@ -35,6 +44,8 @@ import org.springframework.security.core.GrantedAuthority; */ public final class SpPermission { + private static final Logger LOGGER = LoggerFactory.getLogger(SpPermission.class); + /** * Permission to read the targets from the * {@link ProvisioningTargetRepository} including their meta information, @@ -139,6 +150,53 @@ public final class SpPermission { // Constants only } + /** + * Return all permission. + * + * @return all permission + */ + public static Collection getAllAuthorities() { + return getAllAuthorities(Collections.emptyList()); + } + + /** + * Return all permission. + * + * @param exclusionRoles + * roles which will excluded + * @return all permissions + */ + public static Collection getAllAuthorities(final String... exclusionRoles) { + return getAllAuthorities(Arrays.asList(exclusionRoles)); + } + + /** + * Return all permission. + * + * @param exclusionRoles + * roles which will excluded + * @return all permissions + */ + public static Collection getAllAuthorities(final Collection exclusionRoles) { + final List allPermissions = new ArrayList<>(); + final Field[] declaredFields = SpPermission.class.getDeclaredFields(); + for (final Field field : declaredFields) { + if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) { + field.setAccessible(true); + try { + final String role = (String) field.get(null); + if (!(exclusionRoles.contains(role))) { + allPermissions.add(role); + } + } catch (final IllegalAccessException e) { + LOGGER.error(e.getMessage(), e); + } + + } + } + return allPermissions; + } + /** * Contains all the spring security evaluation expressions for the * {@link PreAuthorize} annotation for method security. @@ -166,8 +224,10 @@ public final class SpPermission { /* * Spring security eval expressions. */ - private static final String HAS_AUTH_PREFIX = "hasAuthority('"; - private static final String HAS_AUTH_SUFFIX = "')"; + private static final String BRACKET_OPEN = "("; + private static final String BRACKET_CLOSE = ")"; + private static final String HAS_AUTH_PREFIX = "hasAuthority" + BRACKET_OPEN + "'"; + private static final String HAS_AUTH_SUFFIX = "'" + BRACKET_CLOSE; private static final String HAS_AUTH_AND = " and "; /** @@ -199,99 +259,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_OR = " or "; - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#UPDATE_TARGET}. - */ - public static final String HAS_AUTH_UPDATE_TARGET = HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#SYSTEM_ADMIN}. - */ - public static final String HAS_AUTH_SYSTEM_ADMIN = HAS_AUTH_PREFIX + SYSTEM_ADMIN + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#READ_TARGET}. - */ - public static final String HAS_AUTH_READ_TARGET = HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#CREATE_TARGET}. - */ - public static final String HAS_AUTH_CREATE_TARGET = HAS_AUTH_PREFIX + CREATE_TARGET + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#DELETE_TARGET}. - */ - public static final String HAS_AUTH_DELETE_TARGET = HAS_AUTH_PREFIX + DELETE_TARGET + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#READ_REPOSITORY} and - * {@link SpPermission#UPDATE_TARGET}. - */ - public static final String HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET = HAS_AUTH_PREFIX + READ_REPOSITORY - + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#CREATE_REPOSITORY}. - */ - public static final String HAS_AUTH_CREATE_REPOSITORY = HAS_AUTH_PREFIX + CREATE_REPOSITORY + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#DELETE_REPOSITORY}. - */ - public static final String HAS_AUTH_DELETE_REPOSITORY = HAS_AUTH_PREFIX + DELETE_REPOSITORY + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#READ_REPOSITORY}. - */ - public static final String HAS_AUTH_READ_REPOSITORY = HAS_AUTH_PREFIX + READ_REPOSITORY + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#UPDATE_REPOSITORY}. - */ - public static final String HAS_AUTH_UPDATE_REPOSITORY = HAS_AUTH_PREFIX + UPDATE_REPOSITORY + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#READ_REPOSITORY} and - * {@link SpPermission#READ_TARGET}. - */ - public static final String HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET = HAS_AUTH_PREFIX + READ_REPOSITORY - + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#DOWNLOAD_REPOSITORY_ARTIFACT}. - */ - public static final String HAS_AUTH_DOWNLOAD_ARTIFACT = HAS_AUTH_PREFIX + DOWNLOAD_REPOSITORY_ARTIFACT - + HAS_AUTH_SUFFIX; - - /** - * Spring security eval hasAnyRole expression to check if the spring - * context contains the anoynmous role or the controller specific role - * {@link SpPermission#CONTROLLER_ROLE}. - */ - public static final String IS_CONTROLLER = "hasAnyRole('" + CONTROLLER_ROLE_ANONYMOUS + "', '" + CONTROLLER_ROLE - + "')"; - - /** - * Spring security eval hasAuthority expression to check if the spring - * context contains the role to allow controllers to download specific - * role {@link SpPermission#CONTROLLER_DOWNLOAD_ROLE}. - */ - public static final String HAS_CONTROLLER_DOWNLOAD = HAS_AUTH_PREFIX + CONTROLLER_DOWNLOAD_ROLE - + HAS_AUTH_SUFFIX; - /** * Spring security eval hasAnyRole expression to check if the spring * context contains system code role @@ -301,33 +268,168 @@ public final class SpPermission { /** * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#CREATE_REPOSITORY} and - * {@link SpPermission#CREATE_TARGET}. + * context contains {@link SpPermission#UPDATE_TARGET} or + * {@link #IS_SYSTEM_CODE}. */ - public static final String HAS_AUTH_CREATE_REPOSITORY_AND_CREATE_TARGET = HAS_AUTH_PREFIX + CREATE_REPOSITORY - + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + CREATE_TARGET + HAS_AUTH_SUFFIX; + public static final String HAS_AUTH_UPDATE_TARGET = HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX + + HAS_AUTH_OR + IS_SYSTEM_CODE; /** * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#ROLLOUT_MANAGEMENT} + * context contains {@link SpPermission#SYSTEM_ADMIN} or + * {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_SYSTEM_ADMIN = HAS_AUTH_PREFIX + SYSTEM_ADMIN + HAS_AUTH_SUFFIX + + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#READ_TARGET} or + * {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_READ_TARGET = HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX + HAS_AUTH_OR + + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#CREATE_TARGET} or + * {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_CREATE_TARGET = HAS_AUTH_PREFIX + CREATE_TARGET + HAS_AUTH_SUFFIX + + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#DELETE_TARGET} or + * {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_DELETE_TARGET = HAS_AUTH_PREFIX + DELETE_TARGET + HAS_AUTH_SUFFIX + + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#READ_REPOSITORY} and + * {@link SpPermission#UPDATE_TARGET} or {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET = BRACKET_OPEN + HAS_AUTH_PREFIX + + READ_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX + + BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#CREATE_REPOSITORY} or + * {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_CREATE_REPOSITORY = HAS_AUTH_PREFIX + CREATE_REPOSITORY + HAS_AUTH_SUFFIX + + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#DELETE_REPOSITORY} or + * {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_DELETE_REPOSITORY = HAS_AUTH_PREFIX + DELETE_REPOSITORY + HAS_AUTH_SUFFIX + + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#READ_REPOSITORY} or + * {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_READ_REPOSITORY = HAS_AUTH_PREFIX + READ_REPOSITORY + HAS_AUTH_SUFFIX + + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#UPDATE_REPOSITORY} or + * {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_UPDATE_REPOSITORY = HAS_AUTH_PREFIX + UPDATE_REPOSITORY + HAS_AUTH_SUFFIX + + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#READ_REPOSITORY} and + * {@link SpPermission#READ_TARGET} or {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET = BRACKET_OPEN + HAS_AUTH_PREFIX + + READ_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX + + BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#DOWNLOAD_REPOSITORY_ARTIFACT} or + * {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_DOWNLOAD_ARTIFACT = HAS_AUTH_PREFIX + DOWNLOAD_REPOSITORY_ARTIFACT + + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAnyRole expression to check if the spring + * context contains the anoynmous role or the controller specific role + * {@link SpringEvalExpressions#CONTROLLER_ROLE}. + */ + public static final String IS_CONTROLLER = "hasAnyRole('" + CONTROLLER_ROLE_ANONYMOUS + "', '" + CONTROLLER_ROLE + + "')"; + + /** + * Spring security eval hasAuthority expression to check if the spring + * context contains the role to allow controllers to download specific + * role {@link SpringEvalExpressions#CONTROLLER_DOWNLOAD_ROLE} + */ + public static final String HAS_CONTROLLER_DOWNLOAD = HAS_AUTH_PREFIX + CONTROLLER_DOWNLOAD_ROLE + + HAS_AUTH_SUFFIX; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#CREATE_REPOSITORY} and + * {@link SpPermission#CREATE_TARGET} or {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_CREATE_REPOSITORY_AND_CREATE_TARGET = BRACKET_OPEN + HAS_AUTH_PREFIX + + CREATE_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + CREATE_TARGET + HAS_AUTH_SUFFIX + + BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#ROLLOUT_MANAGEMENT} or + * {@link #IS_SYSTEM_CODE}. */ public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_READ = HAS_AUTH_PREFIX + ROLLOUT_MANAGEMENT - + HAS_AUTH_SUFFIX; + + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#ROLLOUT_MANAGEMENT} and - * {@link SpPermission#UPDATE_TARGET}. + * {@link SpPermission#READ_TARGET} or {@link #IS_SYSTEM_CODE}. */ - public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE = HAS_AUTH_PREFIX + ROLLOUT_MANAGEMENT - + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX; + public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ = BRACKET_OPEN + HAS_AUTH_PREFIX + + ROLLOUT_MANAGEMENT + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX + + BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE; /** * Spring security eval hasAuthority expression to check if spring - * context contains {@link SpPermission#TENANT_CONFIGURATION} + * context contains {@link SpPermission#ROLLOUT_MANAGEMENT} and + * {@link SpPermission#UPDATE_TARGET} or {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE = BRACKET_OPEN + HAS_AUTH_PREFIX + + ROLLOUT_MANAGEMENT + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + UPDATE_TARGET + + HAS_AUTH_SUFFIX + BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#TENANT_CONFIGURATION} or + * {@link #IS_SYSTEM_CODE}. */ public static final String HAS_AUTH_TENANT_CONFIGURATION = HAS_AUTH_PREFIX + TENANT_CONFIGURATION - + HAS_AUTH_SUFFIX; + + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; + + /** + * Spring security eval hasAuthority expression to check if spring + * context contains {@link SpPermission#SYSTEM_MONITOR} or + * {@link #IS_SYSTEM_CODE}. + */ + public static final String HAS_AUTH_SYSTEM_MONITOR = HAS_AUTH_PREFIX + SYSTEM_MONITOR + HAS_AUTH_SUFFIX + + HAS_AUTH_OR + IS_SYSTEM_CODE; private SpringEvalExpressions() { // utility class diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java index f0d8f7d48..008aa3e95 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java @@ -8,8 +8,10 @@ */ package org.eclipse.hawkbit.security; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.eclipse.hawkbit.security.SecurityConstants.SECURITY_LOG_PREFIX; + import java.io.IOException; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; @@ -31,25 +33,21 @@ import com.google.common.cache.CacheBuilder; /** * Filter for protection against denial of service attacks. It reduces the * maximum number of request per seconds which can be separately configured for - * read (GET) and write (PUT/POST/DELETE) requests. requests - * - * - * - * + * read (GET) and write (PUT/POST/DELETE) requests. */ public class DosFilter extends OncePerRequestFilter { private static final Logger LOG = LoggerFactory.getLogger(DosFilter.class); - private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos"); - private static final Logger LOG_BLACKLIST = LoggerFactory.getLogger("server-security.blacklist"); + private static final Logger LOG_DOS = LoggerFactory.getLogger(SECURITY_LOG_PREFIX + ".dos"); + private static final Logger LOG_BLACKLIST = LoggerFactory.getLogger(SECURITY_LOG_PREFIX + ".blacklist"); private final Pattern ipAdressBlacklist; - private final Cache readCountCache = CacheBuilder.newBuilder() - .expireAfterAccess(1, TimeUnit.SECONDS).build(); + private final Cache readCountCache = CacheBuilder.newBuilder().expireAfterAccess(1, SECONDS) + .build(); - private final Cache writeCountCache = CacheBuilder.newBuilder() - .expireAfterAccess(1, TimeUnit.SECONDS).build(); + private final Cache writeCountCache = CacheBuilder.newBuilder().expireAfterAccess(1, SECONDS) + .build(); private final Integer maxRead; private final Integer maxWrite; @@ -78,7 +76,7 @@ public class DosFilter extends OncePerRequestFilter { */ public DosFilter(final Integer maxRead, final Integer maxWrite, final String ipDosWhiteListPattern, final String ipBlackListPattern, final String forwardHeader) { - super(); + this.maxRead = maxRead; this.maxWrite = maxWrite; this.forwardHeader = forwardHeader; @@ -96,21 +94,13 @@ public class DosFilter extends OncePerRequestFilter { } } - /* - * (non-Javadoc) - * - * @see - * org.springframework.web.filter.OncePerRequestFilter#doFilterInternal( - * javax.servlet.http. HttpServletRequest, - * javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain) - */ @Override protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException { boolean processChain; - final String ip = IpUtil.getClientIpFromRequest(request, forwardHeader).getHost(); + final String ip = IpUtil.getClientIpFromRequest(request, forwardHeader, true).getHost(); if (checkIpFails(ip)) { processChain = handleMissingIpAddress(response); } else { @@ -152,11 +142,9 @@ public class DosFilter extends OncePerRequestFilter { } private static boolean handleMissingIpAddress(final HttpServletResponse response) { - boolean processChain; LOG.error("Failed to get peer IP adress"); response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); - processChain = false; - return processChain; + return false; } private boolean handleWriteRequest(final HttpServletResponse response, final String ip) { diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java index 6192a8f31..3f0be994a 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java @@ -82,10 +82,16 @@ public class HawkbitSecurityProperties { private String blacklist = ""; /** - * Name of the http header from which the remote ip is extracted. + * Name of the http header from which the remote ip is extracted for DDI + * connected clients. */ private String remoteIpHeader = "X-Forwarded-For"; + /** + * Set to true if DDI clients remote IP should be stored. + */ + private boolean trackRemoteIp = true; + public String getBlacklist() { return blacklist; } @@ -101,6 +107,14 @@ public class HawkbitSecurityProperties { public void setRemoteIpHeader(final String remoteIpHeader) { this.remoteIpHeader = remoteIpHeader; } + + public boolean isTrackRemoteIp() { + return trackRemoteIp; + } + + public void setTrackRemoteIp(final boolean trackRemoteIp) { + this.trackRemoteIp = trackRemoteIp; + } } /** diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java new file mode 100644 index 000000000..7285404a8 --- /dev/null +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java @@ -0,0 +1,24 @@ +/** + * 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; + +/** + * Constants related to security. + */ +public final class SecurityConstants { + + /** + * Logger prefix used for security logging. + */ + public static final String SECURITY_LOG_PREFIX = "server-security"; + + private SecurityConstants() { + + } +} diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java index 2d8ac52df..f2cfbbdbf 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java @@ -8,13 +8,16 @@ */ package org.eclipse.hawkbit.security; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Collection; +import java.util.Collections; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextImpl; /** * A {@link TenantAware} implemenation which retrieves the ID of the tenant from @@ -22,15 +25,9 @@ import org.springframework.security.core.context.SecurityContextHolder; * {@link Authentication#getDetails()} which holds the * {@link TenantAwareAuthenticationDetails} object. * - * - * - * */ public class SecurityContextTenantAware implements TenantAware { - private static final ThreadLocal TENANT_THREAD_LOCAL = new ThreadLocal<>(); - private static final ThreadLocal RUN_AS_DEPTH = new ThreadLocal<>(); - /* * (non-Javadoc) * @@ -38,9 +35,6 @@ public class SecurityContextTenantAware implements TenantAware { */ @Override public String getCurrentTenant() { - if (TENANT_THREAD_LOCAL.get() != null) { - return TENANT_THREAD_LOCAL.get(); - } final SecurityContext context = SecurityContextHolder.getContext(); if (context.getAuthentication() != null) { final Object authDetails = context.getAuthentication().getDetails(); @@ -51,29 +45,96 @@ public class SecurityContextTenantAware implements TenantAware { return null; } - /* - * (non-Javadoc) - * - * @see hawkbit.server.tenancy.TenantAware#runAsTenant(java.lang.String, - * java.util.concurrent.Callable) - */ @Override public T runAsTenant(final String tenant, final TenantRunner callable) { - AtomicInteger runAsDepth = RUN_AS_DEPTH.get(); - if (runAsDepth == null) { - runAsDepth = new AtomicInteger(1); - RUN_AS_DEPTH.set(runAsDepth); - } else { - runAsDepth.incrementAndGet(); - } - TENANT_THREAD_LOCAL.set(tenant); + final SecurityContext originalContext = SecurityContextHolder.getContext(); try { + SecurityContextHolder.setContext(buildSecurityContext(tenant)); return callable.run(); } finally { - if (runAsDepth.decrementAndGet() <= 0) { - RUN_AS_DEPTH.remove(); - TENANT_THREAD_LOCAL.remove(); + SecurityContextHolder.setContext(originalContext); + } + } + + private SecurityContext buildSecurityContext(final String tenant) { + final SecurityContextImpl securityContext = new SecurityContextImpl(); + securityContext.setAuthentication( + new AuthenticationDelegate(SecurityContextHolder.getContext().getAuthentication(), tenant)); + return securityContext; + } + + /** + * An {@link Authentication} implementation to delegate to an existing + * {@link Authentication} object except setting the details specifically for + * a specific tenant. + */ + private class AuthenticationDelegate implements Authentication { + private static final long serialVersionUID = 1L; + + private final Authentication delegate; + private final TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails; + + private AuthenticationDelegate(final Authentication delegate, final String tenant) { + this.delegate = delegate; + tenantAwareAuthenticationDetails = new TenantAwareAuthenticationDetails(tenant, false); + } + + @Override + public boolean equals(final Object another) { + if (delegate != null) { + return delegate.equals(another); + } else if (another == null) { + return true; } + return false; + } + + @Override + public String toString() { + return (delegate != null) ? delegate.toString() : null; + } + + @Override + public int hashCode() { + return (delegate != null) ? delegate.hashCode() : -1; + } + + @Override + public String getName() { + return (delegate != null) ? delegate.getName() : null; + } + + @Override + public Collection getAuthorities() { + return (delegate != null) ? delegate.getAuthorities() : Collections.emptyList(); + } + + @Override + public Object getCredentials() { + return (delegate != null) ? delegate.getCredentials() : null; + } + + @Override + public Object getDetails() { + return tenantAwareAuthenticationDetails; + } + + @Override + public Object getPrincipal() { + return (delegate != null) ? delegate.getPrincipal() : null; + } + + @Override + public boolean isAuthenticated() { + return (delegate != null) ? delegate.isAuthenticated() : true; + } + + @Override + public void setAuthenticated(final boolean isAuthenticated) { + if (delegate == null) { + return; + } + delegate.setAuthenticated(isAuthenticated); } } } diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java index 2d225c1dc..472e32493 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java @@ -14,12 +14,8 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; /** - * Auditor class that allows {@link BaseEntity}s to insert currenlt logged in - * user for repository changes. - * - * - * - * + * Auditor class that allows BaseEntitys to insert current logged in user for + * repository changes. * */ public class SpringSecurityAuditorAware implements AuditorAware { @@ -29,16 +25,21 @@ public class SpringSecurityAuditorAware implements AuditorAware { final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null || !authentication.isAuthenticated()) { + if (isAuthenticationInvalid(authentication)) { return null; } - if (authentication.getPrincipal() != null) { - if (authentication.getPrincipal() instanceof UserDetails) { - return ((UserDetails) authentication.getPrincipal()).getUsername(); - } - return authentication.getPrincipal().toString(); + return getCurrentAuditor(authentication); + } + + private String getCurrentAuditor(final Authentication authentication) { + if (authentication.getPrincipal() instanceof UserDetails) { + return ((UserDetails) authentication.getPrincipal()).getUsername(); } - return null; + return authentication.getPrincipal().toString(); + } + + private static boolean isAuthenticationInvalid(final Authentication authentication) { + return authentication == null || !authentication.isAuthenticated() || authentication.getPrincipal() == null; } } diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java index e0f3ca8c7..979080344 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java @@ -34,7 +34,7 @@ import com.google.common.base.Throwables; @Service public class SystemSecurityContext { - private static final Logger LOGGER = LoggerFactory.getLogger(SystemSecurityContext.class); + private static final Logger logger = LoggerFactory.getLogger(SystemSecurityContext.class); private final TenantAware tenantAware; @@ -60,27 +60,55 @@ public class SystemSecurityContext { * The security context will be switched to the system code and back after * the callable is called. * + * The system code is executed for a current tenant by using the + * {@link TenantAware#getCurrentTenant()}. + * * @param callable * the callable to call within the system security context * @return the return value of the {@link Callable#call()} method. */ + // Exception squid:S2221 - Callable declares Exception + @SuppressWarnings("squid:S2221") public T runAsSystem(final Callable callable) { + return runAsSystemAsTenant(callable, tenantAware.getCurrentTenant()); + } + + /** + * Runs a given {@link Callable} within a system security context, which is + * permitted to call secured system code. Often the system needs to call + * secured methods by it's own without relying on the current security + * context e.g. if the current security context does not contain the + * necessary permission it's necessary to execute code as system code to + * execute necessary methods and functionality. + * + * The security context will be switched to the system code and back after + * the callable is called. + * + * The system code is executed for a specific given tenant by using the + * {@link TenantAware}. + * + * @param callable + * the callable to call within the system security context + * @param tenant + * the tenant to act as system code + * @return the return value of the {@link Callable#call()} method. + */ + public T runAsSystemAsTenant(final Callable callable, final String tenant) { final SecurityContext oldContext = SecurityContextHolder.getContext(); try { - LOGGER.debug("entering system code execution"); - return tenantAware.runAsTenant(tenantAware.getCurrentTenant(), () -> { + logger.debug("entering system code execution"); + return tenantAware.runAsTenant(tenant, () -> { try { - setSystemContext(); + setSystemContext(SecurityContextHolder.getContext()); return callable.call(); - // The callable API throws a Exception and not a specific - } catch (@SuppressWarnings("squid:S2221") final Exception e) { + } catch (final Exception e) { throw Throwables.propagate(e); } }); } finally { SecurityContextHolder.setContext(oldContext); - LOGGER.debug("leaving system code execution"); + logger.debug("leaving system code execution"); } } @@ -92,20 +120,30 @@ public class SystemSecurityContext { return SecurityContextHolder.getContext().getAuthentication() instanceof SystemCodeAuthentication; } - private static void setSystemContext() { + private static void setSystemContext(final SecurityContext oldContext) { + final Authentication oldAuthentication = oldContext.getAuthentication(); final SecurityContextImpl securityContextImpl = new SecurityContextImpl(); - securityContextImpl.setAuthentication(new SystemCodeAuthentication()); + securityContextImpl.setAuthentication(new SystemCodeAuthentication(oldAuthentication)); SecurityContextHolder.setContext(securityContextImpl); } /** - * Authentication with the system role. + * An implementation of the Spring's {@link Authentication} object which is + * used within a system security code block and wraps the original + * authentication object. The wrapped object contains the necessary + * {@link SpringEvalExpressions#SYSTEM_ROLE} which is allowed to execute all + * secured methods. */ public static class SystemCodeAuthentication implements Authentication { private static final long serialVersionUID = 1L; private static final List AUTHORITIES = Collections .singletonList(new SimpleGrantedAuthority(SpringEvalExpressions.SYSTEM_ROLE)); + private final Authentication oldAuthentication; + + private SystemCodeAuthentication(final Authentication oldAuthentication) { + this.oldAuthentication = oldAuthentication; + } @Override public String getName() { @@ -119,17 +157,17 @@ public class SystemSecurityContext { @Override public Object getCredentials() { - return null; + return oldAuthentication != null ? oldAuthentication.getCredentials() : null; } @Override public Object getDetails() { - return null; + return oldAuthentication != null ? oldAuthentication.getDetails() : null; } @Override public Object getPrincipal() { - return null; + return oldAuthentication != null ? oldAuthentication.getPrincipal() : null; } @Override diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java index 4e08d8bfe..c7778f776 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java @@ -15,6 +15,8 @@ import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; +import org.eclipse.hawkbit.security.HawkbitSecurityProperties; + import com.google.common.net.HttpHeaders; /** @@ -24,6 +26,7 @@ import com.google.common.net.HttpHeaders; */ public final class IpUtil { + private static final String HIDDEN_IP = "***"; private static final String SCHEME_SEPERATOR = "://"; private static final String HTTP_SCHEME = "http"; private static final String AMPQP_SCHEME = "amqp"; @@ -45,17 +48,49 @@ public final class IpUtil { * @param request * the {@link HttpServletRequest} to determine the IP address * where this request has been sent from - * @param forwardHeader - * the header name containing the IP address e.g. forwarded by a - * proxy {@code x-forwarded-for} + * @param securityProperties + * hawkBit security properties. * @return the {@link URI} based IP address from the client which sent the * request */ - public static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader) { - String ip = request.getHeader(forwardHeader); - if (ip == null || (ip = findClientIpAddress(ip)) == null) { - ip = request.getRemoteAddr(); + public static URI getClientIpFromRequest(final HttpServletRequest request, + final HawkbitSecurityProperties securityProperties) { + + return getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader(), + securityProperties.getClients().isTrackRemoteIp()); + } + + /** + * Retrieves the string based IP address from a given + * {@link HttpServletRequest} by either the + * {@link HttpHeaders#X_FORWARDED_FOR} or by the + * {@link HttpServletRequest#getRemoteAddr()} methods. + * + * @param request + * the {@link HttpServletRequest} to determine the IP address + * where this request has been sent from + * @param forwardHeader + * the header name containing the IP address e.g. forwarded by a + * proxy {@code x-forwarded-for} + * + * @param trackRemoteIp + * to true if remote IP should be tracked. + * @return the {@link URI} based IP address from the client which sent the + * request + */ + public static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader, + final boolean trackRemoteIp) { + String ip; + + if (trackRemoteIp) { + ip = request.getHeader(forwardHeader); + if (ip == null || (ip = findClientIpAddress(ip)) == null) { + ip = request.getRemoteAddr(); + } + } else { + ip = HIDDEN_IP; } + return createHttpUri(ip); } @@ -144,4 +179,17 @@ public final class IpUtil { public static boolean isAmqpUri(final URI uri) { return uri != null && AMPQP_SCHEME.equals(uri.getScheme()); } + + /** + * Check if the IP address of that {@link URI} is known, i.e. not an AQMP + * exchange in DMF case and not HIDDEN_IP in DDI case. + * + * @param uri + * the uri + * @return true if IP address is actually known by the server + */ + public static boolean isIpAddresKnown(final URI uri) { + return uri != null && !(AMPQP_SCHEME.equals(uri.getScheme()) || HIDDEN_IP.equals(uri.getHost())); + } + } diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/PermissionTest.java b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/PermissionTest.java new file mode 100644 index 000000000..2c948206e --- /dev/null +++ b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/PermissionTest.java @@ -0,0 +1,56 @@ +/** + * 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.im.authentication; + +import static org.fest.assertions.api.Assertions.assertThat; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.Test; +import org.springframework.context.annotation.Description; +import org.springframework.security.core.GrantedAuthority; + +import ru.yandex.qatools.allure.annotations.Features; +import ru.yandex.qatools.allure.annotations.Stories; + +/** + * Test {@link SpPermission}. + */ +@Features("Unit Tests - Security") +@Stories("Permission Test") +public final class PermissionTest { + + @Test + @Description("Verify the get permission function") + public void testGetPermissions() { + final int allPermission = 15; + final int permissionWithoutSystem = allPermission - 3; + final Collection allAuthorities = SpPermission.getAllAuthorities(); + final List allAuthoritiesList = PermissionUtils.createAllAuthorityList(); + assertThat(allAuthorities).hasSize(allPermission); + // times 2 because we add also all authorities as prefix 'ROLE_'; + assertThat(allAuthoritiesList).hasSize(allPermission * 2); + assertThat(allAuthoritiesList.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())) + .containsAll(allAuthorities); + + final Collection authoritiesWithoutSystem = SpPermission.getAllAuthorities(SpPermission.SYSTEM_ADMIN, + SpPermission.SYSTEM_DIAG, SpPermission.SYSTEM_MONITOR); + final List authoritiesListWithoutSystem = PermissionUtils.createAuthorityList(SpPermission + .getAllAuthorities(SpPermission.SYSTEM_ADMIN, SpPermission.SYSTEM_DIAG, SpPermission.SYSTEM_MONITOR)); + + assertThat(authoritiesWithoutSystem).hasSize(permissionWithoutSystem); + // times 2 because we add also all authorities as prefix 'ROLE_'; + assertThat(authoritiesListWithoutSystem).hasSize(permissionWithoutSystem * 2); + assertThat(authoritiesListWithoutSystem.stream().map(authority -> authority.getAuthority()) + .collect(Collectors.toList())).containsAll(authoritiesWithoutSystem); + + } +} diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java index 9eb83d2a9..0f4a01d26 100644 --- a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java +++ b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java @@ -50,7 +50,7 @@ public class IpUtilTest { when(requestMock.getRemoteAddr()).thenReturn(knownRemoteClientIP.getHost()); // test - final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux"); + final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux", true); // verify assertThat(remoteAddr).as("The remote address should be as the known client IP address") @@ -59,6 +59,25 @@ public class IpUtilTest { verify(requestMock, times(1)).getRemoteAddr(); } + @Test + @Description("Tests create uri from request with masked IP when IP tracking is disabled") + public void maskRemoteAddrIfDisabled() { + // known values + final URI knownRemoteClientIP = IpUtil.createHttpUri("***"); + // mock + when(requestMock.getHeader(HttpHeaders.X_FORWARDED_FOR)).thenReturn(null); + when(requestMock.getRemoteAddr()).thenReturn(knownRemoteClientIP.getHost()); + + // test + final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux", false); + + // verify + assertThat(remoteAddr).as("The remote address should be as the known client IP address") + .isEqualTo(knownRemoteClientIP); + verify(requestMock, times(0)).getHeader("bumlux"); + verify(requestMock, times(0)).getRemoteAddr(); + } + @Test @Description("Tests create uri from x forward header") public void getRemoteAddrFromXForwardedForHeader() { @@ -69,7 +88,7 @@ public class IpUtilTest { when(requestMock.getRemoteAddr()).thenReturn(null); // test - final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "X-Forwarded-For"); + final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "X-Forwarded-For", true); // verify assertThat(remoteAddr).as("The remote address should be as the known client IP address") diff --git a/hawkbit-security-integration/pom.xml b/hawkbit-security-integration/pom.xml index c17317b3d..455e3ece1 100644 --- a/hawkbit-security-integration/pom.xml +++ b/hawkbit-security-integration/pom.xml @@ -23,7 +23,7 @@ org.eclipse.hawkbit - hawkbit-repository + hawkbit-repository-api ${project.version} @@ -37,6 +37,12 @@ + + org.eclipse.hawkbit + hawkbit-repository-jpa + ${project.version} + test + junit junit diff --git a/hawkbit-ui/pom.xml b/hawkbit-ui/pom.xml index e0bde576a..b90e36e88 100644 --- a/hawkbit-ui/pom.xml +++ b/hawkbit-ui/pom.xml @@ -8,8 +8,7 @@ http://www.eclipse.org/legal/epl-v10.html --> - + 4.0.0 org.eclipse.hawkbit @@ -28,8 +27,8 @@ -Xmx1g -Xss1024k - ${project.build.directory}/classes/VAADIN/widgetsets - ${project.build.directory}/classes/VAADIN/widgetsets + src/main/resources/VAADIN/widgetsets + src/main/resources/VAADIN/widgetsets src/main/resources true @@ -43,12 +42,12 @@ + process-classes - clean resources update-theme update-widgetset @@ -58,29 +57,47 @@ - - org.apache.maven.plugins - maven-jar-plugin - - - true - - true - true - - - CustomRenderers - 1 - org.eclipse.hawkbit.ui.customrenderers.CustomRendererWidgetSet - - - - + + org.apache.maven.plugins + maven-antrun-plugin + + + process-classes + + + + + + + + + run + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + true + + true + true + + + CustomRenderers + 1 + org.eclipse.hawkbit.ui.customrenderers.CustomRendererWidgetSet + + + + - + org.eclipse.m2e lifecycle-mapping @@ -151,7 +168,7 @@ org.eclipse.hawkbit - hawkbit-repository + hawkbit-repository-api ${project.version} @@ -171,11 +188,11 @@ com.vaadin vaadin-server - - com.vaadin - vaadin-client - - + + com.vaadin + vaadin-client + + com.vaadin vaadin-push @@ -183,6 +200,10 @@ org.springframework.security spring-security-web + + org.apache.commons + commons-collections4 + com.vaadin @@ -229,6 +250,12 @@ + + org.eclipse.hawkbit + hawkbit-repository-jpa + ${project.version} + test + org.mockito mockito-core @@ -254,5 +281,10 @@ allure-junit-adaptor test + + org.scala-lang + scala-library + 2.10.4 + \ No newline at end of file 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 4358bb734..cca4bdd4c 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 @@ -11,18 +11,18 @@ package org.eclipse.hawkbit.ui; import java.util.HashSet; import java.util.Set; -import org.eclipse.hawkbit.eventbus.event.DistributionSetTagCreatedBulkEvent; -import org.eclipse.hawkbit.eventbus.event.DistributionSetTagDeletedEvent; -import org.eclipse.hawkbit.eventbus.event.DistributionSetTagUpdateEvent; import org.eclipse.hawkbit.eventbus.event.Event; -import org.eclipse.hawkbit.eventbus.event.RolloutChangeEvent; -import org.eclipse.hawkbit.eventbus.event.RolloutGroupChangeEvent; -import org.eclipse.hawkbit.eventbus.event.TargetCreatedEvent; 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; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagCreatedBulkEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetTagCreatedBulkEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetTagDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetTagUpdateEvent; /** * The default hawkbit event provider. diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactBeanQuery.java index 017bda863..cb869714b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactBeanQuery.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Map; import org.eclipse.hawkbit.repository.ArtifactManagement; +import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; @@ -27,18 +28,14 @@ import org.vaadin.addons.lazyquerycontainer.QueryDefinition; /** * Simple implementation of generics bean query which dynamically loads artifact * beans. - * - * - * - * - * */ public class ArtifactBeanQuery extends AbstractBeanQuery { private static final long serialVersionUID = -333786310371208962L; private Sort sort = new Sort(Direction.DESC, "filename"); - private transient ArtifactManagement artifactManagement; - private transient Page firstPagetArtifacts; - private Long baseSwModuleId; + private transient ArtifactManagement artifactManagement = null; + private transient EntityFactory entityFactory; + private transient Page firstPagetArtifacts = null; + private Long baseSwModuleId = null; /** * Parametric Constructor. @@ -72,7 +69,7 @@ public class ArtifactBeanQuery extends AbstractBeanQuery { @Override protected LocalArtifact constructBean() { - return new LocalArtifact(); + return entityFactory.generateLocalArtifact(); } @Override @@ -115,4 +112,11 @@ public class ArtifactBeanQuery extends AbstractBeanQuery { } return artifactManagement; } + + private EntityFactory getEntityFactory() { + if (entityFactory == null) { + entityFactory = SpringContextHelper.getBean(EntityFactory.class); + } + return entityFactory; + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsLayout.java index 7c5d4153f..c62637117 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsLayout.java @@ -31,7 +31,7 @@ import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.I18N; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.SpringContextHelper; @@ -260,7 +260,7 @@ public class ArtifactDetailsLayout extends VerticalLayout { final String fileName = (String) table.getContainerDataSource().getItem(itemId) .getItemProperty(PROVIDED_FILE_NAME).getValue(); final Button deleteIcon = SPUIComponentProvider.getButton( - fileName + "-" + SPUIComponetIdProvider.UPLOAD_FILE_DELETE_ICON, "", + fileName + "-" + SPUIComponentIdProvider.UPLOAD_FILE_DELETE_ICON, "", SPUILabelDefinitions.DISCARD, ValoTheme.BUTTON_TINY + " " + "redicon", true, FontAwesome.TRASH_O, SPUIButtonStyleSmallNoBorder.class); deleteIcon.setData(itemId); @@ -344,7 +344,7 @@ public class ArtifactDetailsLayout extends VerticalLayout { detailsTable.setImmediate(true); detailsTable.setSizeFull(); - detailsTable.setId(SPUIComponetIdProvider.UPLOAD_ARTIFACT_DETAILS_TABLE); + detailsTable.setId(SPUIComponentIdProvider.UPLOAD_ARTIFACT_DETAILS_TABLE); detailsTable.addStyleName(ValoTheme.TABLE_NO_VERTICAL_LINES); detailsTable.addStyleName(ValoTheme.TABLE_SMALL); return detailsTable; @@ -385,7 +385,7 @@ public class ArtifactDetailsLayout extends VerticalLayout { */ public void createMaxArtifactDetailsTable() { maxArtifactDetailsTable = createArtifactDetailsTable(); - maxArtifactDetailsTable.setId(SPUIComponetIdProvider.UPLOAD_ARTIFACT_DETAILS_TABLE_MAX); + maxArtifactDetailsTable.setId(SPUIComponentIdProvider.UPLOAD_ARTIFACT_DETAILS_TABLE_MAX); maxArtifactDetailsTable.setContainerDataSource(artifactDetailsTable.getContainerDataSource()); addGeneratedColumn(maxArtifactDetailsTable); if (!readOnly) { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleTypeEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleTypeEvent.java index 88e076775..7262aee72 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleTypeEvent.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleTypeEvent.java @@ -12,17 +12,11 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType; /** * Event to represent software module type add, update or delete. - * - * - * */ public class SoftwareModuleTypeEvent { /** * Software module type events in the Upload UI. - * - * - * */ public enum SoftwareModuleTypeEnum { ADD_SOFTWARE_MODULE_TYPE, DELETE_SOFTWARE_MODULE_TYPE, UPDATE_SOFTWARE_MODULE_TYPE diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java index 3d75b67a7..e1fe4e07f 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java @@ -15,6 +15,5 @@ package org.eclipse.hawkbit.ui.artifacts.event; * */ public enum UploadArtifactUIEvent { - - SHOW_DROP_HINTS, HIDE_DROP_HINTS, SOFTWARE_DRAG_START, SOFTWARE_TYPE_DRAG_START, UPDATE_UPLOAD_COUNT, ENABLE_PROCESS_BUTTON, HIDE_FILTER_BY_TYPE, SHOW_FILTER_BY_TYPE, DISCARD_DELETE_SOFTWARE, DISCARD_ALL_DELETE_SOFTWARE, DELETED_ALL_SOFWARE, DISABLE_PROCESS_BUTTON, DISCARD_DELETE_SOFTWARE_TYPE, DISCARD_ALL_DELETE_SOFTWARE_TYPE, DELETED_ALL_SOFWARE_TYPE + SHOW_DROP_HINTS, HIDE_DROP_HINTS, SOFTWARE_DRAG_START, SOFTWARE_TYPE_DRAG_START, UPDATE_UPLOAD_COUNT, HIDE_FILTER_BY_TYPE, SHOW_FILTER_BY_TYPE, DISCARD_DELETE_SOFTWARE, DISCARD_ALL_DELETE_SOFTWARE, DELETED_ALL_SOFWARE, DISCARD_DELETE_SOFTWARE_TYPE, DISCARD_ALL_DELETE_SOFTWARE_TYPE, DELETED_ALL_SOFWARE_TYPE, MINIMIZED_STATUS_POPUP, MAXIMIZED_STATUS_POPUP, UPLOAD_IN_PROGESS, ARTIFACT_RESULT_POPUP_CLOSED } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadFileStatus.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadFileStatus.java new file mode 100644 index 000000000..90ad5c0f0 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadFileStatus.java @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.artifacts.event; + +import java.io.Serializable; + +import org.eclipse.hawkbit.repository.model.SoftwareModule; + +/** + * + * Holds file and upload status details.Meta data sent with upload events. + * + */ +public class UploadFileStatus implements Serializable { + + private static final long serialVersionUID = -3599629192216760811L; + + private String fileName; + + private long contentLength; + + private long bytesRead; + + private String failureReason; + + private SoftwareModule softwareModule; + + public UploadFileStatus(String fileName) { + this.fileName = fileName; + } + + public UploadFileStatus(String fileName, long bytesRead, long contentLength,SoftwareModule softwareModule) { + this.fileName = fileName; + this.contentLength = contentLength; + this.bytesRead = bytesRead; + this.softwareModule = softwareModule; + } + + public UploadFileStatus(String fileName, String failureReason,SoftwareModule selectedSw) { + this.failureReason = failureReason; + this.fileName = fileName; + this.softwareModule = selectedSw; + } + + public String getFileName() { + return fileName; + } + + public long getContentLength() { + return contentLength; + } + + public long getBytesRead() { + return bytesRead; + } + + public String getFailureReason() { + return failureReason; + } + + public SoftwareModule getSoftwareModule() { + return softwareModule; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadStatusEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadStatusEvent.java new file mode 100644 index 000000000..3b4767c60 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadStatusEvent.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.artifacts.event; +/** + * + * Holds the upload file status. + * + */ +public class UploadStatusEvent { + + public enum UploadStatusEventType { + UPLOAD_FAILED, UPLOAD_IN_PROGRESS, UPLOAD_STARTED, UPLOAD_FINISHED, UPLOAD_SUCCESSFUL, UPLOAD_STREAMING_FAILED, UPLOAD_STREAMING_FINISHED, ABORT_UPLOAD + } + + private UploadStatusEventType uploadProgressEventType; + + private UploadFileStatus uploadStatus; + + public UploadStatusEvent(UploadStatusEventType eventType, UploadFileStatus entity) { + this.uploadProgressEventType = eventType; + this.uploadStatus = entity; + } + + public UploadFileStatus getUploadStatus() { + return uploadStatus; + } + + public void setUploadStatus(UploadFileStatus uploadStatus) { + this.uploadStatus = uploadStatus; + } + + public UploadStatusEventType getUploadProgressEventType() { + return uploadProgressEventType; + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadViewAcceptCriteria.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadViewAcceptCriteria.java index 060800fb8..8cfeaea81 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadViewAcceptCriteria.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadViewAcceptCriteria.java @@ -14,7 +14,7 @@ import java.util.List; import java.util.Map; import org.eclipse.hawkbit.ui.common.AbstractAcceptCriteria; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import com.vaadin.spring.annotation.SpringComponent; import com.vaadin.spring.annotation.ViewScope; @@ -37,8 +37,8 @@ public class UploadViewAcceptCriteria extends AbstractAcceptCriteria { @Override protected String getComponentId(final Component component) { String id = component.getId(); - if (id != null && id.startsWith(SPUIComponetIdProvider.UPLOAD_TYPE_BUTTON_PREFIX)) { - id = SPUIComponetIdProvider.UPLOAD_TYPE_BUTTON_PREFIX; + if (id != null && id.startsWith(SPUIComponentIdProvider.UPLOAD_TYPE_BUTTON_PREFIX)) { + id = SPUIComponentIdProvider.UPLOAD_TYPE_BUTTON_PREFIX; } return id; } @@ -56,16 +56,16 @@ public class UploadViewAcceptCriteria extends AbstractAcceptCriteria { private static Map> createDropConfigurations() { final Map> config = new HashMap<>(); // Delete drop area droppable components - config.put(SPUIComponetIdProvider.DELETE_BUTTON_WRAPPER_ID, Arrays.asList( - SPUIComponetIdProvider.UPLOAD_SOFTWARE_MODULE_TABLE, SPUIComponetIdProvider.UPLOAD_TYPE_BUTTON_PREFIX)); + config.put(SPUIComponentIdProvider.DELETE_BUTTON_WRAPPER_ID, Arrays.asList( + SPUIComponentIdProvider.UPLOAD_SOFTWARE_MODULE_TABLE, SPUIComponentIdProvider.UPLOAD_TYPE_BUTTON_PREFIX)); return config; } private static Map createDropHintConfigurations() { final Map config = new HashMap<>(); - config.put(SPUIComponetIdProvider.UPLOAD_TYPE_BUTTON_PREFIX, UploadArtifactUIEvent.SOFTWARE_TYPE_DRAG_START); - config.put(SPUIComponetIdProvider.UPLOAD_SOFTWARE_MODULE_TABLE, UploadArtifactUIEvent.SOFTWARE_DRAG_START); + config.put(SPUIComponentIdProvider.UPLOAD_TYPE_BUTTON_PREFIX, UploadArtifactUIEvent.SOFTWARE_TYPE_DRAG_START); + config.put(SPUIComponentIdProvider.UPLOAD_SOFTWARE_MODULE_TABLE, UploadArtifactUIEvent.SOFTWARE_DRAG_START); return config; } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/footer/SMDeleteActionsLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/footer/SMDeleteActionsLayout.java index 4cb28c2c3..49f232bd0 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/footer/SMDeleteActionsLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/footer/SMDeleteActionsLayout.java @@ -16,7 +16,7 @@ import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; import org.eclipse.hawkbit.ui.common.footer.AbstractDeleteActionsLayout; import org.eclipse.hawkbit.ui.common.table.AbstractTable; import org.eclipse.hawkbit.ui.management.event.DragEvent; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.springframework.beans.factory.annotation.Autowired; import org.vaadin.spring.events.EventScope; @@ -114,7 +114,7 @@ public class SMDeleteActionsLayout extends AbstractDeleteActionsLayout { @Override protected String getDeleteAreaId() { - return SPUIComponetIdProvider.DELETE_BUTTON_WRAPPER_ID; + return SPUIComponentIdProvider.DELETE_BUTTON_WRAPPER_ID; } @Override @@ -130,10 +130,10 @@ public class SMDeleteActionsLayout extends AbstractDeleteActionsLayout { addToDeleteList(sourceTable, (TableTransferable) event.getTransferable()); updateSWActionCount(); } - if (sourceComponent.getId().startsWith(SPUIComponetIdProvider.UPLOAD_TYPE_BUTTON_PREFIX)) { + if (sourceComponent.getId().startsWith(SPUIComponentIdProvider.UPLOAD_TYPE_BUTTON_PREFIX)) { final String swModuleTypeName = sourceComponent.getId() - .replace(SPUIComponetIdProvider.UPLOAD_TYPE_BUTTON_PREFIX, ""); + .replace(SPUIComponentIdProvider.UPLOAD_TYPE_BUTTON_PREFIX, ""); if (artifactUploadState.getSoftwareModuleFilters().getSoftwareModuleType().isPresent() && artifactUploadState.getSoftwareModuleFilters().getSoftwareModuleType().get().getName() .equalsIgnoreCase(swModuleTypeName)) { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/footer/UploadViewConfirmationWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/footer/UploadViewConfirmationWindowLayout.java index e6284d5d6..49b271b6b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/footer/UploadViewConfirmationWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/footer/UploadViewConfirmationWindowLayout.java @@ -21,7 +21,7 @@ import org.eclipse.hawkbit.ui.artifacts.state.CustomFile; import org.eclipse.hawkbit.ui.common.confirmwindow.layout.AbstractConfirmationWindowLayout; import org.eclipse.hawkbit.ui.common.confirmwindow.layout.ConfirmationTab; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.springframework.beans.factory.annotation.Autowired; @@ -77,7 +77,7 @@ public class UploadViewConfirmationWindowLayout extends AbstractConfirmationWind private ConfirmationTab createSMDeleteConfirmationTab() { final ConfirmationTab tab = new ConfirmationTab(); - tab.getConfirmAll().setId(SPUIComponetIdProvider.SW_DELETE_ALL); + tab.getConfirmAll().setId(SPUIComponentIdProvider.SW_DELETE_ALL); tab.getConfirmAll().setIcon(FontAwesome.TRASH_O); tab.getConfirmAll().setCaption(i18n.get("button.delete.all")); tab.getConfirmAll().addClickListener(event -> deleteSMAll(tab)); @@ -181,7 +181,7 @@ public class UploadViewConfirmationWindowLayout extends AbstractConfirmationWind private ConfirmationTab createSMtypeDeleteConfirmationTab() { final ConfirmationTab tab = new ConfirmationTab(); - tab.getConfirmAll().setId(SPUIComponetIdProvider.SAVE_DELETE_SW_MODULE_TYPE); + tab.getConfirmAll().setId(SPUIComponentIdProvider.SAVE_DELETE_SW_MODULE_TYPE); tab.getConfirmAll().setIcon(FontAwesome.TRASH_O); tab.getConfirmAll().setCaption(i18n.get("button.delete.all")); tab.getConfirmAll().addClickListener(event -> deleteSMtypeAll(tab)); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/ProxyBaseSoftwareModuleItem.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/ProxyBaseSoftwareModuleItem.java index 6e417435c..1559a9bec 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/ProxyBaseSoftwareModuleItem.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/ProxyBaseSoftwareModuleItem.java @@ -10,8 +10,6 @@ package org.eclipse.hawkbit.ui.artifacts.smtable; import java.security.SecureRandom; -import org.eclipse.hawkbit.repository.model.SoftwareModule; - /** * * Proxy for software module to display details in Software modules table. @@ -19,7 +17,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; * * */ -public class ProxyBaseSoftwareModuleItem extends SoftwareModule { +public class ProxyBaseSoftwareModuleItem { private static final long serialVersionUID = -1555306616599140635L; @@ -39,6 +37,11 @@ public class ProxyBaseSoftwareModuleItem extends SoftwareModule { private String modifiedByUser; + private String name; + private String version; + private String vendor; + private String description; + /** * Default constructor. */ @@ -47,6 +50,38 @@ public class ProxyBaseSoftwareModuleItem extends SoftwareModule { swId = RANDOM_OBJ.nextLong(); } + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(final String version) { + this.version = version; + } + + public String getVendor() { + return vendor; + } + + public void setVendor(final String vendor) { + this.vendor = vendor; + } + + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + public String getCreatedByUser() { return createdByUser; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java index 1e4029087..c8eb74313 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java @@ -10,47 +10,43 @@ package org.eclipse.hawkbit.ui.artifacts.smtable; import java.io.Serializable; +import javax.annotation.PostConstruct; + +import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent; +import org.eclipse.hawkbit.ui.common.CommonDialogWindow; import org.eclipse.hawkbit.ui.common.SoftwareModuleTypeBeanQuery; import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; -import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder; +import org.eclipse.hawkbit.ui.decorators.SPUIWindowDecorator; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.I18N; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; -import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; import org.eclipse.hawkbit.ui.utils.UINotification; import org.springframework.beans.factory.annotation.Autowired; import org.vaadin.addons.lazyquerycontainer.BeanQueryFactory; import org.vaadin.spring.events.EventBus; -import com.vaadin.server.FontAwesome; import com.vaadin.spring.annotation.SpringComponent; import com.vaadin.spring.annotation.ViewScope; -import com.vaadin.ui.Alignment; -import com.vaadin.ui.Button; import com.vaadin.ui.ComboBox; -import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.CustomComponent; +import com.vaadin.ui.FormLayout; import com.vaadin.ui.Label; import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; -import com.vaadin.ui.UI; -import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; import com.vaadin.ui.themes.ValoTheme; /** * Generates window for Software module add or update. - * - * */ @SpringComponent @ViewScope -public class SoftwareModuleAddUpdateWindow implements Serializable { +public class SoftwareModuleAddUpdateWindow extends CustomComponent implements Serializable { private static final long serialVersionUID = -5217675246477211483L; @@ -66,7 +62,8 @@ public class SoftwareModuleAddUpdateWindow implements Serializable { @Autowired private transient SoftwareManagement softwareManagement; - private Label madatoryLabel; + @Autowired + private transient EntityFactory entityFactory; private TextField nameTextField; @@ -74,35 +71,34 @@ public class SoftwareModuleAddUpdateWindow implements Serializable { private TextField vendorTextField; - private Button saveSoftware; - - private Button closeWindow; - private ComboBox typeComboBox; private TextArea descTextArea; - private Window window; - - private String oldDescriptionValue; - - private String oldVendorValue; + private CommonDialogWindow window; private Boolean editSwModule = Boolean.FALSE; private Long baseSwModuleId; + private FormLayout formLayout; + + /** + * Initialize Distribution Add and Edit Window. + */ + @PostConstruct + void init() { + createRequiredComponents(); + } + /** * Create window for new software module. * * @return reference of {@link com.vaadin.ui.Window} to add new software * module. */ - public Window createAddSoftwareModuleWindow() { - editSwModule = Boolean.FALSE; - createRequiredComponents(); - createWindow(); - return window; + public CommonDialogWindow createAddSoftwareModuleWindow() { + return createUpdateSoftwareModuleWindow(null); } /** @@ -113,185 +109,114 @@ public class SoftwareModuleAddUpdateWindow implements Serializable { * @return reference of {@link com.vaadin.ui.Window} to update software * module. */ - public Window createUpdateSoftwareModuleWindow(final Long baseSwModuleId) { - editSwModule = Boolean.TRUE; + public CommonDialogWindow createUpdateSoftwareModuleWindow(final Long baseSwModuleId) { this.baseSwModuleId = baseSwModuleId; - createRequiredComponents(); - createWindow(); - /* populate selected target values to edit. */ + resetComponents(); populateValuesOfSwModule(); - nameTextField.setEnabled(false); - versionTextField.setEnabled(false); - typeComboBox.setEnabled(false); + createWindow(); return window; } private void createRequiredComponents() { /* name textfield */ - nameTextField = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY, true, null, - i18n.get("textfield.name"), true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); - nameTextField.setId(SPUIComponetIdProvider.SOFT_MODULE_NAME); + nameTextField = SPUIComponentProvider.getTextField(i18n.get("textfield.name"), "", ValoTheme.TEXTFIELD_TINY, + true, null, i18n.get("textfield.name"), true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); + nameTextField.setId(SPUIComponentIdProvider.SOFT_MODULE_NAME); /* version text field */ - versionTextField = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY, true, null, - i18n.get("textfield.version"), true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); - versionTextField.setId(SPUIComponetIdProvider.SOFT_MODULE_VERSION); + versionTextField = SPUIComponentProvider.getTextField(i18n.get("textfield.version"), "", + ValoTheme.TEXTFIELD_TINY, true, null, i18n.get("textfield.version"), true, + SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); + versionTextField.setId(SPUIComponentIdProvider.SOFT_MODULE_VERSION); /* Vendor text field */ - vendorTextField = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY, false, null, - i18n.get("textfield.vendor"), true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); - vendorTextField.setId(SPUIComponetIdProvider.SOFT_MODULE_VENDOR); + vendorTextField = SPUIComponentProvider.getTextField(i18n.get("textfield.vendor"), "", ValoTheme.TEXTFIELD_TINY, + false, null, i18n.get("textfield.vendor"), true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); + vendorTextField.setId(SPUIComponentIdProvider.SOFT_MODULE_VENDOR); - descTextArea = SPUIComponentProvider.getTextArea("text-area-style", ValoTheme.TEXTAREA_TINY, false, null, - i18n.get("textfield.description"), SPUILabelDefinitions.TEXT_AREA_MAX_LENGTH); - descTextArea.setId(SPUIComponetIdProvider.ADD_SW_MODULE_DESCRIPTION); - addDescriptionTextChangeListener(); - addVendorTextChangeListener(); + descTextArea = SPUIComponentProvider.getTextArea(i18n.get("textfield.description"), "text-area-style", + ValoTheme.TEXTAREA_TINY, false, null, i18n.get("textfield.description"), + SPUILabelDefinitions.TEXT_AREA_MAX_LENGTH); + descTextArea.setId(SPUIComponentIdProvider.ADD_SW_MODULE_DESCRIPTION); - /* Label for mandatory symbol */ - madatoryLabel = new Label(i18n.get("label.mandatory.field")); - madatoryLabel.setStyleName(SPUIStyleDefinitions.SP_TEXTFIELD_ERROR); - madatoryLabel.addStyleName(ValoTheme.LABEL_SMALL); - - typeComboBox = SPUIComponentProvider.getComboBox("", "", null, null, false, null, - i18n.get("upload.swmodule.type")); - typeComboBox.setId(SPUIComponetIdProvider.SW_MODULE_TYPE); + typeComboBox = SPUIComponentProvider.getComboBox(i18n.get("upload.swmodule.type"), "", "", null, null, true, + null, i18n.get("upload.swmodule.type")); + typeComboBox.setId(SPUIComponentIdProvider.SW_MODULE_TYPE); typeComboBox.setStyleName(SPUIDefinitions.COMBO_BOX_SPECIFIC_STYLE + " " + ValoTheme.COMBOBOX_TINY); typeComboBox.setNewItemsAllowed(Boolean.FALSE); typeComboBox.setImmediate(Boolean.TRUE); - populateTypeNameCombo(); - - /* save or update button */ - saveSoftware = SPUIComponentProvider.getButton(SPUIComponetIdProvider.SOFT_MODULE_SAVE, "", "", "", true, - FontAwesome.SAVE, SPUIButtonStyleSmallNoBorder.class); - saveSoftware.addClickListener(event -> { - if (editSwModule) { - updateSwModule(); - } else { - /* add new or update software module */ - addNewBaseSoftware(); - } - }); - - /* close button */ - closeWindow = SPUIComponentProvider.getButton(SPUIComponetIdProvider.SOFT_MODULE_DISCARD, "", "", "", true, - FontAwesome.TIMES, SPUIButtonStyleSmallNoBorder.class); - /* Just close this window when this button is clicked */ - closeWindow.addClickListener(event -> closeThisWindow()); - - resetOldValues(); } - /** - * - */ private void populateTypeNameCombo() { typeComboBox.setContainerDataSource(HawkbitCommonUtil.createLazyQueryContainer( new BeanQueryFactory(SoftwareModuleTypeBeanQuery.class))); typeComboBox.setItemCaptionPropertyId(SPUILabelDefinitions.VAR_NAME); - } - private void resetOldValues() { - oldDescriptionValue = null; - oldVendorValue = null; + private void resetComponents() { + + vendorTextField.clear(); + nameTextField.clear(); + versionTextField.clear(); + descTextArea.clear(); + typeComboBox.clear(); + editSwModule = Boolean.FALSE; } - /** - * Keep UI components on Layout. - * - * @return - */ private void createWindow() { - /* action button layout (save & dicard) */ - final HorizontalLayout buttonsLayout = new HorizontalLayout(); - buttonsLayout.setSizeFull(); - buttonsLayout.addComponents(saveSoftware, closeWindow); - buttonsLayout.setComponentAlignment(saveSoftware, Alignment.BOTTOM_LEFT); - buttonsLayout.setComponentAlignment(closeWindow, Alignment.BOTTOM_RIGHT); - buttonsLayout.addStyleName("window-style"); - final Label madatoryStarLabel = new Label("*"); madatoryStarLabel.setStyleName("v-caption v-required-field-indicator"); madatoryStarLabel.setWidth(null); - final HorizontalLayout hLayout = new HorizontalLayout(); - hLayout.setSizeFull(); - hLayout.addComponents(typeComboBox, madatoryStarLabel); - hLayout.setComponentAlignment(typeComboBox, Alignment.TOP_LEFT); - hLayout.setComponentAlignment(madatoryStarLabel, Alignment.TOP_RIGHT); - hLayout.setExpandRatio(typeComboBox, 0.8f); + addStyleName("lay-color"); + setSizeUndefined(); - /* - * The main layout of the window contains mandatory info, textboxes - * (controller Id, name & description) and action buttons layout - */ - final VerticalLayout mainLayout = new VerticalLayout(); - mainLayout.setSpacing(Boolean.TRUE); - mainLayout.addStyleName("lay-color"); - mainLayout.addComponent(madatoryLabel); - mainLayout.setComponentAlignment(madatoryLabel, Alignment.MIDDLE_LEFT); - mainLayout.addComponent(hLayout); - mainLayout.setComponentAlignment(hLayout, Alignment.MIDDLE_LEFT); - mainLayout.addComponents(nameTextField, versionTextField, vendorTextField, descTextArea, buttonsLayout); - - /* add main layout to the window */ - window = SPUIComponentProvider.getWindow(i18n.get("upload.caption.add.new.swmodule"), null, - SPUIDefinitions.CREATE_UPDATE_WINDOW); - window.setContent(mainLayout); - window.setModal(true); - nameTextField.focus(); + formLayout = new FormLayout(); + formLayout.setCaption(null); + formLayout.addComponent(typeComboBox); + formLayout.addComponent(nameTextField); + formLayout.addComponent(versionTextField); + formLayout.addComponent(vendorTextField); + formLayout.addComponent(descTextArea); + + setCompositionRoot(formLayout); + + window = SPUIWindowDecorator.getWindow(i18n.get("upload.caption.add.new.swmodule"), null, + SPUIDefinitions.CREATE_UPDATE_WINDOW, this, event -> saveOrUpdate(), null, null, formLayout, i18n); + window.getButtonsLayout().removeStyleName("actionButtonsMargin"); + + nameTextField.setEnabled(!editSwModule); + versionTextField.setEnabled(!editSwModule); + typeComboBox.setEnabled(!editSwModule); + + typeComboBox.focus(); } - private void addDescriptionTextChangeListener() { - descTextArea.addTextChangeListener(event -> { - if (event.getText().equals(oldDescriptionValue) && vendorTextField.getValue().equals(oldVendorValue)) { - saveSoftware.setEnabled(false); - } else { - saveSoftware.setEnabled(true); - } - }); - } - - private void addVendorTextChangeListener() { - vendorTextField.addTextChangeListener(event -> { - if (event.getText().equals(oldVendorValue) && descTextArea.getValue().equals(oldDescriptionValue)) { - saveSoftware.setEnabled(false); - } else { - saveSoftware.setEnabled(true); - } - }); - } - - /** - * Add new SW module. - */ private void addNewBaseSoftware() { final String name = HawkbitCommonUtil.trimAndNullIfEmpty(nameTextField.getValue()); final String version = HawkbitCommonUtil.trimAndNullIfEmpty(versionTextField.getValue()); final String vendor = HawkbitCommonUtil.trimAndNullIfEmpty(vendorTextField.getValue()); final String description = HawkbitCommonUtil.trimAndNullIfEmpty(descTextArea.getValue()); final String type = typeComboBox.getValue() != null ? typeComboBox.getValue().toString() : null; - if (mandatoryCheck(name, version, type)) { - if (HawkbitCommonUtil.isDuplicate(name, version, type)) { - uiNotifcation.displayValidationError( - i18n.get("message.duplicate.softwaremodule", new Object[] { name, version })); - } else { - final SoftwareModule newBaseSoftwareModule = HawkbitCommonUtil.addNewBaseSoftware(name, version, vendor, - softwareManagement.findSoftwareModuleTypeByName(type), description); - if (newBaseSoftwareModule != null) { - /* display success message */ - uiNotifcation.displaySuccess(i18n.get("message.save.success", new Object[] { - newBaseSoftwareModule.getName() + ":" + newBaseSoftwareModule.getVersion() })); - eventBus.publish(this, - new SoftwareModuleEvent(BaseEntityEventType.NEW_ENTITY, newBaseSoftwareModule)); - } - // close the window - closeThisWindow(); + + if (HawkbitCommonUtil.isDuplicate(name, version, type)) { + uiNotifcation.displayValidationError( + i18n.get("message.duplicate.softwaremodule", new Object[] { name, version })); + } else { + final SoftwareModule newBaseSoftwareModule = HawkbitCommonUtil.addNewBaseSoftware(entityFactory, name, + version, vendor, softwareManagement.findSoftwareModuleTypeByName(type), description); + if (newBaseSoftwareModule != null) { + /* display success message */ + uiNotifcation.displaySuccess(i18n.get("message.save.success", + new Object[] { newBaseSoftwareModule.getName() + ":" + newBaseSoftwareModule.getVersion() })); + eventBus.publish(this, new SoftwareModuleEvent(BaseEntityEventType.NEW_ENTITY, newBaseSoftwareModule)); } } } + /** + * updates a softwareModule + */ private void updateSwModule() { final String newDesc = HawkbitCommonUtil.trimAndNullIfEmpty(descTextArea.getValue()); final String newVendor = HawkbitCommonUtil.trimAndNullIfEmpty(vendorTextField.getValue()); @@ -305,10 +230,16 @@ public class SoftwareModuleAddUpdateWindow implements Serializable { eventBus.publish(this, new SoftwareModuleEvent(BaseEntityEventType.UPDATED_ENTITY, newSWModule)); } - closeThisWindow(); } + /** + * fill the data of a softwareModule in the content of the window + */ private void populateValuesOfSwModule() { + if (baseSwModuleId == null) { + return; + } + editSwModule = Boolean.TRUE; final SoftwareModule swModle = softwareManagement.findSoftwareModuleById(baseSwModuleId); nameTextField.setValue(swModle.getName()); versionTextField.setValue(swModle.getVersion()); @@ -316,48 +247,22 @@ public class SoftwareModuleAddUpdateWindow implements Serializable { : HawkbitCommonUtil.trimAndNullIfEmpty(swModle.getVendor())); descTextArea.setValue(swModle.getDescription() == null ? HawkbitCommonUtil.SP_STRING_EMPTY : HawkbitCommonUtil.trimAndNullIfEmpty(swModle.getDescription())); - oldDescriptionValue = descTextArea.getValue(); - oldVendorValue = vendorTextField.getValue(); if (swModle.getType().isDeleted()) { typeComboBox.addItem(swModle.getType().getName()); } typeComboBox.setValue(swModle.getType().getName()); - saveSoftware.setEnabled(Boolean.FALSE); } - /** - * Method to close window. - */ - private void closeThisWindow() { - window.close(); - UI.getCurrent().removeWindow(window); - } - - /** - * Validation check - Mandatory. - * - * @param name - * as String - * @param version - * as version - * @return boolena as flag - */ - private boolean mandatoryCheck(final String name, final String version, final String type) { - boolean isValid = true; - if (name == null || version == null || type == null) { - if (name == null) { - nameTextField.addStyleName(SPUIStyleDefinitions.SP_TEXTFIELD_ERROR); - } - if (version == null) { - versionTextField.addStyleName(SPUIStyleDefinitions.SP_TEXTFIELD_ERROR); - } - if (type == null) { - typeComboBox.addStyleName(SPUIStyleDefinitions.SP_COMBOFIELD_ERROR); - } - - uiNotifcation.displayValidationError(i18n.get("message.mandatory.check")); - isValid = false; + private void saveOrUpdate() { + if (editSwModule) { + updateSwModule(); + } else { + addNewBaseSoftware(); } - return isValid; } + + public FormLayout getFormLayout() { + return formLayout; + } + } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleDetails.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleDetails.java index 9d535f7f5..653994a17 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleDetails.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleDetails.java @@ -14,7 +14,7 @@ import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; import org.eclipse.hawkbit.ui.common.detailslayout.AbstractNamedVersionedEntityTableDetailsLayout; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.springframework.beans.factory.annotation.Autowired; import org.vaadin.spring.events.EventScope; import org.vaadin.spring.events.annotation.EventBusListenerMethod; @@ -47,7 +47,7 @@ public class SoftwareModuleDetails extends AbstractNamedVersionedEntityTableDeta @Override protected String getEditButtonId() { - return SPUIComponetIdProvider.UPLOAD_SW_MODULE_EDIT_BUTTON; + return SPUIComponentIdProvider.UPLOAD_SW_MODULE_EDIT_BUTTON; } @Override @@ -90,19 +90,19 @@ public class SoftwareModuleDetails extends AbstractNamedVersionedEntityTableDeta final Label vendorLabel = SPUIComponentProvider.createNameValueLabel(getI18n().get("label.dist.details.vendor"), HawkbitCommonUtil.trimAndNullIfEmpty(vendor) == null ? "" : vendor); - vendorLabel.setId(SPUIComponetIdProvider.DETAILS_VENDOR_LABEL_ID); + vendorLabel.setId(SPUIComponentIdProvider.DETAILS_VENDOR_LABEL_ID); detailsTabLayout.addComponent(vendorLabel); if (type != null) { final Label typeLabel = SPUIComponentProvider.createNameValueLabel(getI18n().get("label.dist.details.type"), type); - typeLabel.setId(SPUIComponetIdProvider.DETAILS_TYPE_LABEL_ID); + typeLabel.setId(SPUIComponentIdProvider.DETAILS_TYPE_LABEL_ID); detailsTabLayout.addComponent(typeLabel); } final Label assignLabel = SPUIComponentProvider.createNameValueLabel(getI18n().get("label.assigned.type"), HawkbitCommonUtil.trimAndNullIfEmpty(maxAssign) == null ? "" : maxAssign); - assignLabel.setId(SPUIComponetIdProvider.SWM_DTLS_MAX_ASSIGN); + assignLabel.setId(SPUIComponentIdProvider.SWM_DTLS_MAX_ASSIGN); detailsTabLayout.addComponent(assignLabel); } @@ -139,6 +139,6 @@ public class SoftwareModuleDetails extends AbstractNamedVersionedEntityTableDeta @Override protected String getDetailsHeaderCaptionId() { - return SPUIComponetIdProvider.TARGET_DETAILS_HEADER_LABEL_ID; + return SPUIComponentIdProvider.TARGET_DETAILS_HEADER_LABEL_ID; } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java index 478438891..56367f230 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java @@ -22,7 +22,7 @@ import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; import org.eclipse.hawkbit.ui.common.table.AbstractNamedVersionTable; import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.TableColumn; @@ -44,7 +44,6 @@ import com.vaadin.ui.UI; /** * Header of Software module table. - * */ @SpringComponent @ViewScope @@ -75,7 +74,7 @@ public class SoftwareModuleTable extends AbstractNamedVersionTable selectors; - private Color selectedColor; - private ColorPickerGradient colorSelect; - private Slider redSlider; - private Slider greenSlider; - private Slider blueSlider; - private Window swTypeWindow; - protected boolean tagPreviewBtnClicked = false; - private VerticalLayout comboLayout; - private VerticalLayout sliders; - private VerticalLayout colorPickerLayout; - private HorizontalLayout mainLayout; - private VerticalLayout fieldLayout; - /** RGB color converter. */ - private final Coordinates2Color rgbConverter = new CoordinatesToColor(); - - /** - * Initialize the artifact details layout. - */ - public void init() { - createComponents(); - buildLayout(); - addListeners(); + @Override + protected void addListeners() { + super.addListeners(); + optiongroup.addValueChangeListener(this::optionValueChanged); } - private void createComponents() { - createTypeStr = i18n.get("label.create.type"); - updateTypeStr = i18n.get("label.update.type"); + @Override + protected void createRequiredComponents() { + + super.createRequiredComponents(); + singleAssignStr = i18n.get("label.singleAssign.type"); multiAssignStr = i18n.get("label.multiAssign.type"); - createType = SPUIComponentProvider.getLabel(createTypeStr, null); - updateType = SPUIComponentProvider.getLabel(updateTypeStr, null); singleAssign = SPUIComponentProvider.getLabel(singleAssignStr, null); multiAssign = SPUIComponentProvider.getLabel(multiAssignStr, null); - comboLabel = SPUIComponentProvider.getLabel(i18n.get("label.choose.type"), null); - madatoryLabel = getMandatoryLabel(); - colorLabel = SPUIComponentProvider.getLabel(i18n.get("label.choose.type.color"), null); - colorLabel.addStyleName(SPUIDefinitions.COLOR_LABEL_STYLE); - typeName = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY + " " + SPUIDefinitions.TYPE_NAME, - true, "", i18n.get("textfield.name"), true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); - typeName.setId(SPUIDefinitions.NEW_SOFTWARE_TYPE_NAME); + tagName = SPUIComponentProvider.getTextField(i18n.get("textfield.name"), "", + ValoTheme.TEXTFIELD_TINY + " " + SPUIDefinitions.TYPE_NAME, true, "", i18n.get("textfield.name"), true, + SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); + tagName.setId(SPUIDefinitions.NEW_SOFTWARE_TYPE_NAME); - typeKey = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY + " " + SPUIDefinitions.TYPE_KEY, - true, "", i18n.get("textfield.key"), true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); + typeKey = SPUIComponentProvider.getTextField(i18n.get("textfield.key"), "", + ValoTheme.TEXTFIELD_TINY + " " + SPUIDefinitions.TYPE_KEY, true, "", i18n.get("textfield.key"), true, + SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); typeKey.setId(SPUIDefinitions.NEW_SOFTWARE_TYPE_KEY); - typeDesc = SPUIComponentProvider.getTextArea("", ValoTheme.TEXTFIELD_TINY + " " + SPUIDefinitions.TYPE_DESC, - false, "", i18n.get("textfield.description"), SPUILabelDefinitions.TEXT_AREA_MAX_LENGTH); - - typeDesc.setId(SPUIDefinitions.NEW_SOFTWARE_TYPE_DESC); - typeDesc.setImmediate(true); - typeDesc.setNullRepresentation(""); - - typeNameComboBox = SPUIComponentProvider.getComboBox("", "", null, null, false, "", - i18n.get("label.combobox.type")); - typeNameComboBox.addStyleName(SPUIDefinitions.FILTER_TYPE_COMBO_STYLE); - typeNameComboBox.setImmediate(true); - - saveTag = SPUIComponentProvider.getButton(SPUIDefinitions.NEW_SW_TYPE_SAVE, "", "", "", true, FontAwesome.SAVE, - SPUIButtonStyleSmallNoBorder.class); - saveTag.addStyleName(ValoTheme.BUTTON_BORDERLESS); - - discardTag = SPUIComponentProvider.getButton(SPUIDefinitions.NEW_TARGET_TAG_DISRACD, "", "", - "discard-button-style", true, FontAwesome.TIMES, SPUIButtonStyleSmallNoBorder.class); - discardTag.addStyleName(ValoTheme.BUTTON_BORDERLESS); - - tagColorPreviewBtn = new Button(); - tagColorPreviewBtn.setId(SPUIComponetIdProvider.TAG_COLOR_PREVIEW_ID); - getPreviewButtonColor(DEFAULT_COLOR); - tagColorPreviewBtn.setStyleName(TAG_DYNAMIC_STYLE); - - selectors = new HashSet<>(); - selectedColor = new Color(44, 151, 32); - selPreview = new SpColorPickerPreview(selectedColor); - - colorSelect = new ColorPickerGradient("rgb-gradient", rgbConverter); - colorSelect.setColor(selectedColor); - colorSelect.setWidth("220px"); - - redSlider = createRGBSlider("", "red"); - greenSlider = createRGBSlider("", "green"); - blueSlider = createRGBSlider("", "blue"); - setRgbSliderValues(selectedColor); - - createUpdateOptionGroup(); + tagDesc = SPUIComponentProvider.getTextArea(i18n.get("textfield.description"), "", + ValoTheme.TEXTFIELD_TINY + " " + SPUIDefinitions.TYPE_DESC, false, "", + i18n.get("textfield.description"), SPUILabelDefinitions.TEXT_AREA_MAX_LENGTH); + tagDesc.setId(SPUIDefinitions.NEW_SOFTWARE_TYPE_DESC); + tagDesc.setImmediate(true); + tagDesc.setNullRepresentation(""); singleMultiOptionGroup(); - } - private void buildLayout() { - comboLayout = new VerticalLayout(); + @Override + protected void buildLayout() { - sliders = new VerticalLayout(); - sliders.addComponents(redSlider, greenSlider, blueSlider); - - selectors.add(colorSelect); - - colorPickerLayout = new VerticalLayout(); - colorPickerLayout.setStyleName("rgb-vertical-layout"); - colorPickerLayout.addComponent(selPreview); - colorPickerLayout.addComponent(colorSelect); - - fieldLayout = new VerticalLayout(); - fieldLayout.setSpacing(true); - fieldLayout.setMargin(false); - fieldLayout.setWidth("100%"); - fieldLayout.setHeight(null); - fieldLayout.addComponent(createOptiongroup); - fieldLayout.addComponent(comboLayout); - fieldLayout.addComponent(madatoryLabel); - fieldLayout.addComponent(typeName); - fieldLayout.addComponent(typeKey); - fieldLayout.addComponent(typeDesc); - fieldLayout.addComponent(assignOptiongroup); - - final HorizontalLayout colorLabelLayout = new HorizontalLayout(); - colorLabelLayout.addComponents(colorLabel, tagColorPreviewBtn); - fieldLayout.addComponent(colorLabelLayout); - - final HorizontalLayout buttonLayout = new HorizontalLayout(); - buttonLayout.addComponent(saveTag); - buttonLayout.addComponent(discardTag); - buttonLayout.setComponentAlignment(discardTag, Alignment.BOTTOM_RIGHT); - buttonLayout.setComponentAlignment(saveTag, Alignment.BOTTOM_LEFT); - buttonLayout.addStyleName("window-style"); - buttonLayout.setWidth("152px"); - - final VerticalLayout fieldButtonLayout = new VerticalLayout(); - fieldButtonLayout.addComponent(fieldLayout); - fieldButtonLayout.addComponent(buttonLayout); - - mainLayout = new HorizontalLayout(); - mainLayout.addComponent(fieldButtonLayout); - setCompositionRoot(mainLayout); - typeName.focus(); + super.buildLayout(); + ColorPickerHelper.setRgbSliderValues(colorPickerLayout); + getFormLayout().addComponent(typeKey, 4); + getFormLayout().addComponent(assignOptiongroup); } - private void addListeners() { - saveTag.addClickListener(event -> save()); - discardTag.addClickListener(event -> discard()); - colorSelect.addColorChangeListener(this); - selPreview.addColorChangeListener(this); - tagColorPreviewBtn.addClickListener(event -> previewButtonClicked()); - createOptiongroup.addValueChangeListener(event -> createOptionValueChanged(event)); - typeNameComboBox.addValueChangeListener(event -> typeNameChosen(event)); - slidersValueChangeListeners(); - } - - public Window getWindow() { - reset(); - swTypeWindow = SPUIComponentProvider.getWindow(i18n.get("caption.add.type"), null, - SPUIDefinitions.CREATE_UPDATE_WINDOW); - swTypeWindow.setContent(this); - return swTypeWindow; - + @Override + protected String getWindowCaption() { + return i18n.get("caption.add.type"); } /** @@ -286,100 +117,36 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C * @param event * ValueChangeEvent */ - private void createOptionValueChanged(final ValueChangeEvent event) { - if ("Update Type".equals(event.getProperty().getValue())) { - typeName.clear(); - typeDesc.clear(); - typeKey.clear(); - typeKey.setEnabled(false); - typeName.setEnabled(false); + @Override + protected void optionValueChanged(final ValueChangeEvent event) { + + super.optionValueChanged(event); + + if (updateTypeStr.equals(event.getProperty().getValue())) { assignOptiongroup.setEnabled(false); - - populateTypeNameCombo(); - // show target name combo - comboLayout.addComponent(comboLabel); - comboLayout.addComponent(typeNameComboBox); } else { - typeKey.setEnabled(true); - typeName.setEnabled(true); - typeName.clear(); - typeDesc.clear(); - typeKey.clear(); assignOptiongroup.setEnabled(true); - // hide target name combo - comboLayout.removeComponent(comboLabel); - comboLayout.removeComponent(typeNameComboBox); } - // close the color picker layout - tagPreviewBtnClicked = false; - // reset the selected color - Set defualt color - restoreComponentStyles(); - getPreviewButtonColor(DEFAULT_COLOR); - selPreview.setColor(rgbToColorConverter(DEFAULT_COLOR)); - // remove the sliders and color picker layout - fieldLayout.removeComponent(sliders); - mainLayout.removeComponent(colorPickerLayout); - - } - - /** - * Populate Software Module Type name combo. - */ - public void populateTypeNameCombo() { - typeNameComboBox.setContainerDataSource(HawkbitCommonUtil.createLazyQueryContainer( - new BeanQueryFactory(SoftwareModuleTypeBeanQuery.class))); - typeNameComboBox.setItemCaptionPropertyId(SPUILabelDefinitions.VAR_NAME); + assignOptiongroup.select(singleAssignStr); } /** * reset the components. */ - private void reset() { - typeName.setEnabled(true); - typeName.clear(); - typeKey.clear(); - typeDesc.clear(); - restoreComponentStyles(); + @Override + protected void reset() { - // hide target name combo - comboLayout.removeComponent(comboLabel); - comboLayout.removeComponent(typeNameComboBox); - fieldLayout.removeComponent(sliders); - mainLayout.removeComponent(colorPickerLayout); - - createOptiongroup.select(createTypeStr); + super.reset(); assignOptiongroup.select(singleAssignStr); - // Default green color - selectedColor = new Color(44, 151, 32); - selPreview.setColor(selectedColor); - tagPreviewBtnClicked = false; } - private void typeNameChosen(final ValueChangeEvent event) { - final String tagSelected = (String) event.getProperty().getValue(); - if (null != tagSelected) { - setTypeTagCombo(tagSelected); - } else { - resetTagNameField(); - } - } - - private void resetTagNameField() { - typeName.setEnabled(false); - typeName.clear(); + @Override + protected void resetTagNameField() { + super.resetTagNameField(); typeKey.clear(); - typeDesc.clear(); - restoreComponentStyles(); - fieldLayout.removeComponent(sliders); - mainLayout.removeComponent(colorPickerLayout); - + tagDesc.clear(); assignOptiongroup.select(singleAssignStr); - // Default green color - selectedColor = new Color(44, 151, 32); - selPreview.setColor(selectedColor); - tagPreviewBtnClicked = false; - } /** @@ -389,59 +156,23 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C * @param targetTagSelected * as the selected tag from combo */ - private void setTypeTagCombo(final String targetTagSelected) { - typeName.setValue(targetTagSelected); + @Override + protected void setTagDetails(final String targetTagSelected) { + tagName.setValue(targetTagSelected); final SoftwareModuleType selectedTypeTag = swTypeManagementService .findSoftwareModuleTypeByName(targetTagSelected); if (null != selectedTypeTag) { - typeDesc.setValue(selectedTypeTag.getDescription()); + tagDesc.setValue(selectedTypeTag.getDescription()); typeKey.setValue(selectedTypeTag.getKey()); - if (selectedTypeTag.getMaxAssignments() == Integer.MAX_VALUE) { - assignOptiongroup.setValue(multiAssignStr); - } else { + if (selectedTypeTag.getMaxAssignments() == 1) { assignOptiongroup.setValue(singleAssignStr); - } - - if (null == selectedTypeTag.getColour()) { - selectedColor = new Color(44, 151, 32); - selPreview.setColor(selectedColor); - colorSelect.setColor(selectedColor); - createDynamicStyleForComponents(typeName, typeKey, typeDesc, DEFAULT_COLOR); - getPreviewButtonColor(DEFAULT_COLOR); } else { - selectedColor = rgbToColorConverter(selectedTypeTag.getColour()); - selPreview.setColor(selectedColor); - colorSelect.setColor(selectedColor); - createDynamicStyleForComponents(typeName, typeKey, typeDesc, selectedTypeTag.getColour()); - getPreviewButtonColor(selectedTypeTag.getColour()); + assignOptiongroup.setValue(multiAssignStr); } - + setColorPickerComponentsColor(selectedTypeTag.getColour()); } } - /** - * Dynamic styles for window. - * - * @param top - * int value - * @param marginLeft - * int value - */ - private void getPreviewButtonColor(final String color) { - Page.getCurrent().getJavaScript().execute(HawkbitCommonUtil.getPreviewButtonColorScript(color)); - } - - private void createUpdateOptionGroup() { - final List optionValues = new ArrayList<>(); - if (permChecker.hasCreateDistributionPermission()) { - optionValues.add(createType.getValue()); - } - if (permChecker.hasUpdateDistributionPermission()) { - optionValues.add(updateType.getValue()); - } - createOptionGroupByValues(optionValues); - } - private void singleMultiOptionGroup() { final List optionValues = new ArrayList<>(); optionValues.add(singleAssign.getValue()); @@ -449,16 +180,6 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C assignOptionGroupByValues(optionValues); } - private void createOptionGroupByValues(final List tagOptions) { - createOptiongroup = new OptionGroup("", tagOptions); - createOptiongroup.setStyleName(ValoTheme.OPTIONGROUP_SMALL); - createOptiongroup.addStyleName("custom-option-group"); - createOptiongroup.setNullSelectionAllowed(false); - if (!tagOptions.isEmpty()) { - createOptiongroup.select(tagOptions.get(0)); - } - } - private void assignOptionGroupByValues(final List tagOptions) { assignOptiongroup = new OptionGroup("", tagOptions); assignOptiongroup.setStyleName(ValoTheme.OPTIONGROUP_SMALL); @@ -467,156 +188,27 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C assignOptiongroup.select(tagOptions.get(0)); } - private Label getMandatoryLabel() { - final Label label = new Label(i18n.get("label.mandatory.field")); - label.setStyleName(SPUIStyleDefinitions.SP_TEXTFIELD_ERROR + " " + ValoTheme.LABEL_SMALL); - return label; - } - - private Slider createRGBSlider(final String caption, final String styleName) { - final Slider slider = new Slider(caption, 0, 255); - slider.setImmediate(true); - slider.setWidth("150px"); - slider.addStyleName(styleName); - return slider; - } - - private void setRgbSliderValues(final Color color) { - try { - final double redColorValue = color.getRed(); - redSlider.setValue(new Double(redColorValue)); - final double blueColorValue = color.getBlue(); - blueSlider.setValue(new Double(blueColorValue)); - final double greenColorValue = color.getGreen(); - greenSlider.setValue(new Double(greenColorValue)); - } catch (final ValueOutOfBoundsException e) { - LOG.error("Unable to set RGB color value to " + color.getRed() + "," + color.getGreen() + "," - + color.getBlue(), e); + @Override + protected void save(final ClickEvent event) { + final SoftwareModuleType existingSMTypeByKey = swTypeManagementService + .findSoftwareModuleTypeByKey(typeKey.getValue()); + final SoftwareModuleType existingSMTypeByName = swTypeManagementService + .findSoftwareModuleTypeByName(tagName.getValue()); + if (optiongroup.getValue().equals(createTypeStr)) { + if (!checkIsDuplicateByKey(existingSMTypeByKey) && !checkIsDuplicate(existingSMTypeByName)) { + createNewSWModuleType(); + } + } else { + updateSWModuleType(existingSMTypeByName); } } - /** - * Value change listeners implementations of sliders. - */ - private void slidersValueChangeListeners() { - redSlider.addValueChangeListener(new ValueChangeListener() { - private static final long serialVersionUID = -8336732888800920839L; - - @Override - public void valueChange(final ValueChangeEvent event) { - final double red = (Double) event.getProperty().getValue(); - final Color newColor = new Color((int) red, selectedColor.getGreen(), selectedColor.getBlue()); - setColorToComponents(newColor); - } - }); - greenSlider.addValueChangeListener(new ValueChangeListener() { - private static final long serialVersionUID = 1236358037766775663L; - - @Override - public void valueChange(final ValueChangeEvent event) { - final double green = (Double) event.getProperty().getValue(); - final Color newColor = new Color(selectedColor.getRed(), (int) green, selectedColor.getBlue()); - setColorToComponents(newColor); - } - }); - blueSlider.addValueChangeListener(new ValueChangeListener() { - private static final long serialVersionUID = 8466370763686043947L; - - @Override - public void valueChange(final ValueChangeEvent event) { - final double blue = (Double) event.getProperty().getValue(); - final Color newColor = new Color(selectedColor.getRed(), selectedColor.getGreen(), (int) blue); - setColorToComponents(newColor); - } - }); - } - - private void setColorToComponents(final Color newColor) { - setColor(newColor); - colorSelect.setColor(newColor); - getPreviewButtonColor(newColor.getCSS()); - createDynamicStyleForComponents(typeName, typeKey, typeDesc, newColor.getCSS()); - } - - /** - * reset the tag name and tag description component border color. - */ - private void restoreComponentStyles() { - typeName.removeStyleName(TYPE_NAME_DYNAMIC_STYLE); - typeDesc.removeStyleName(TYPE_DESC_DYNAMIC_STYLE); - typeKey.removeStyleName(TYPE_NAME_DYNAMIC_STYLE); - getPreviewButtonColor(DEFAULT_COLOR); - } - - private void save() { - if (mandatoryValuesPresent()) { - final SoftwareModuleType existingType = swTypeManagementService - .findSoftwareModuleTypeByName(typeName.getValue()); - if (createOptiongroup.getValue().equals(createTypeStr)) { - if (!checkIsKeyDuplicate(typeKey.getValue()) && !checkIsDuplicate(existingType)) { - createNewSWModuleType(); - } - } else { - - updateSWModuleType(existingType); - } - } - } - - private boolean checkIsKeyDuplicate(final String key) { - final SoftwareModuleType existingKeyType = swTypeManagementService.findSoftwareModuleTypeByKey(key); - if (existingKeyType != null) { - uiNotification.displayValidationError( - i18n.get("message.type.key.swmodule.duplicate.check", new Object[] { existingKeyType.getKey() })); - return Boolean.TRUE; - } - return Boolean.FALSE; - } - - private Boolean mandatoryValuesPresent() { - if (Strings.isNullOrEmpty(typeName.getValue()) && Strings.isNullOrEmpty(typeKey.getValue())) { - if (createOptiongroup.getValue().equals(createTypeStr)) { - uiNotification.displayValidationError(SPUILabelDefinitions.MISSING_TYPE_NAME_KEY); - } - if (createOptiongroup.getValue().equals(updateTypeStr)) { - if (null == typeNameComboBox.getValue()) { - uiNotification.displayValidationError(i18n.get("message.error.missing.typename")); - } else { - uiNotification.displayValidationError(SPUILabelDefinitions.MISSING_TAG_NAME); - } - } - return Boolean.FALSE; - } - return Boolean.TRUE; - } - - private Boolean checkIsDuplicate(final SoftwareModuleType existingType) { - if (existingType != null) { - uiNotification.displayValidationError( - i18n.get("message.tag.duplicate.check", new Object[] { existingType.getName() })); - return Boolean.TRUE; - } - return Boolean.FALSE; - } - - private void closeWindow() { - swTypeWindow.close(); - UI.getCurrent().removeWindow(swTypeWindow); - } - - private void discard() { - UI.getCurrent().removeWindow(swTypeWindow); - } - - /** - * Create new tag. - */ private void createNewSWModuleType() { int assignNumber = 0; - final String colorPicked = getColorPickedString(); - final String typeNameValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeName.getValue()); + final String colorPicked = ColorPickerHelper.getColorPickedString(getColorPickerLayout().getSelPreview()); + final String typeNameValue = HawkbitCommonUtil.trimAndNullIfEmpty(tagName.getValue()); final String typeKeyValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeKey.getValue()); - final String typeDescValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeDesc.getValue()); + final String typeDescValue = HawkbitCommonUtil.trimAndNullIfEmpty(tagDesc.getValue()); final String assignValue = (String) assignOptiongroup.getValue(); if (null != assignValue && assignValue.equalsIgnoreCase(singleAssignStr)) { assignNumber = 1; @@ -625,121 +217,35 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C } if (null != typeNameValue && null != typeKeyValue) { - SoftwareModuleType newSWType = new SoftwareModuleType(typeKeyValue, typeNameValue, typeDescValue, - assignNumber, colorPicked); - if (null != typeDescValue) { - newSWType.setDescription(typeDescValue); - } - + SoftwareModuleType newSWType = entityFactory.generateSoftwareModuleType(typeKeyValue, typeNameValue, + typeDescValue, assignNumber); + newSWType.setColour(colorPicked); + newSWType.setDescription(typeDescValue); newSWType.setColour(colorPicked); - newSWType = swTypeManagementService.createSoftwareModuleType(newSWType); uiNotification.displaySuccess(i18n.get("message.save.success", new Object[] { newSWType.getName() })); - closeWindow(); eventBus.publish(this, new SoftwareModuleTypeEvent(SoftwareModuleTypeEnum.ADD_SOFTWARE_MODULE_TYPE, newSWType)); - } else { uiNotification.displayValidationError(i18n.get("message.error.missing.typenameorkey")); - } } - /** - * Get color picked value in string. - * - * @return String of color picked value. - */ - private String getColorPickedString() { - return "rgb(" + getSelPreview().getColor().getRed() + "," + getSelPreview().getColor().getGreen() + "," - + getSelPreview().getColor().getBlue() + ")"; - } - - /** - * Color view. - * - * @return ColorPickerPreview as UI - */ - public SpColorPickerPreview getSelPreview() { - return selPreview; - } - - /** - * update tag. - */ private void updateSWModuleType(final SoftwareModuleType existingType) { - final String typeNameValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeName.getValue()); - final String typeDescValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeDesc.getValue()); + final String typeNameValue = HawkbitCommonUtil.trimAndNullIfEmpty(tagName.getValue()); + final String typeDescValue = HawkbitCommonUtil.trimAndNullIfEmpty(tagDesc.getValue()); if (null != typeNameValue) { existingType.setName(typeNameValue); - - existingType.setDescription(null != typeDescValue ? typeDescValue : null); - - existingType.setColour(getColorPickedString()); + existingType.setDescription(typeDescValue); + existingType.setColour(ColorPickerHelper.getColorPickedString(getColorPickerLayout().getSelPreview())); swTypeManagementService.updateSoftwareModuleType(existingType); uiNotification.displaySuccess(i18n.get("message.update.success", new Object[] { existingType.getName() })); - closeWindow(); eventBus.publish(this, new SoftwareModuleTypeEvent(SoftwareModuleTypeEnum.UPDATE_SOFTWARE_MODULE_TYPE, existingType)); - } else { uiNotification.displayValidationError(i18n.get("message.tag.update.mandatory")); } - - } - - /** - * Open color picker on click of preview button. Auto select the color based - * on target tag if already selected. - */ - private void previewButtonClicked() { - if (!tagPreviewBtnClicked) { - final String selectedOption = (String) createOptiongroup.getValue(); - if (null != selectedOption && selectedOption.equalsIgnoreCase(updateTypeStr)) { - if (null != typeNameComboBox.getValue()) { - - final SoftwareModuleType typeSelected = swTypeManagementService - .findSoftwareModuleTypeByName(typeNameComboBox.getValue().toString()); - if (null != typeSelected) { - selectedColor = typeSelected.getColour() != null ? rgbToColorConverter(typeSelected.getColour()) - : rgbToColorConverter(DEFAULT_COLOR); - - } - - } else { - selectedColor = rgbToColorConverter(DEFAULT_COLOR); - } - } - selPreview.setColor(selectedColor); - fieldLayout.addComponent(sliders); - mainLayout.addComponent(colorPickerLayout); - mainLayout.setComponentAlignment(colorPickerLayout, Alignment.BOTTOM_CENTER); - } - tagPreviewBtnClicked = !tagPreviewBtnClicked; - } - - /** - * Covert RGB code to {@Color}. - * - * @param value - * RGB vale - * @return Color - */ - protected Color rgbToColorConverter(final String value) { - if (value.startsWith("rgb")) { - final String[] colors = value.substring(value.indexOf('(') + 1, value.length() - 1).split(","); - final int red = Integer.parseInt(colors[0]); - final int green = Integer.parseInt(colors[1]); - final int blue = Integer.parseInt(colors[2]); - if (colors.length > 3) { - final int alpha = (int) (Double.parseDouble(colors[3]) * 255d); - return new Color(red, green, blue, alpha); - } else { - return new Color(red, green, blue); - } - } - return null; } @Override @@ -753,63 +259,16 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C } - @Override - public void setColor(final Color color) { - if (color == null) { - return; - } - selectedColor = color; - selPreview.setColor(selectedColor); - final String colorPickedPreview = selPreview.getColor().getCSS(); - if (typeName.isEnabled() && null != colorSelect) { - createDynamicStyleForComponents(typeName, typeKey, typeDesc, colorPickedPreview); - colorSelect.setColor(selPreview.getColor()); - } - - } - @Override public Color getColor() { return null; } @Override - public void colorChanged(final ColorChangeEvent event) { - setColor(event.getColor()); - for (final ColorSelector select : selectors) { - if (!event.getSource().equals(select) && select.equals(this) && !select.getColor().equals(selectedColor)) { - select.setColor(selectedColor); - } - } - setRgbSliderValues(selectedColor); - getPreviewButtonColor(event.getColor().getCSS()); - createDynamicStyleForComponents(typeName, typeKey, typeDesc, event.getColor().getCSS()); - } - - /** - * Set tag name and desc field border color based on chosen color. - * - * @param tagName - * @param tagDesc - * @param taregtTagColor - */ - private void createDynamicStyleForComponents(final TextField typeName, final TextField typeKey, - final TextArea typeDesc, final String typeTagColor) { - getTargetDynamicStyles(typeTagColor); - typeName.addStyleName(TYPE_NAME_DYNAMIC_STYLE); - typeKey.addStyleName(TYPE_NAME_DYNAMIC_STYLE); - typeDesc.addStyleName(TYPE_DESC_DYNAMIC_STYLE); - } - - /** - * Get target style - Dynamically as per the color picked, cannot be done - * from the static css. - * - * @param colorPickedPreview - */ - private void getTargetDynamicStyles(final String colorPickedPreview) { - Page.getCurrent().getJavaScript() - .execute(HawkbitCommonUtil.changeToNewSelectedPreviewColor(colorPickedPreview)); + protected void populateTagNameCombo() { + tagNameComboBox.setContainerDataSource(HawkbitCommonUtil.createLazyQueryContainer( + new BeanQueryFactory(SoftwareModuleTypeBeanQuery.class))); + tagNameComboBox.setItemCaptionPropertyId(SPUILabelDefinitions.VAR_NAME); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SMTypeFilterButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SMTypeFilterButtons.java index 5a1736b04..d627a6dd0 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SMTypeFilterButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SMTypeFilterButtons.java @@ -15,7 +15,7 @@ import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; import org.eclipse.hawkbit.ui.common.SoftwareModuleTypeBeanQuery; import org.eclipse.hawkbit.ui.common.filterlayout.AbstractFilterButtons; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.springframework.beans.factory.annotation.Autowired; import org.vaadin.addons.lazyquerycontainer.BeanQueryFactory; import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer; @@ -63,7 +63,7 @@ public class SMTypeFilterButtons extends AbstractFilterButtons { @Override protected String getButtonsTableId() { - return SPUIComponetIdProvider.SW_MODULE_TYPE_TABLE_ID; + return SPUIComponentIdProvider.SW_MODULE_TYPE_TABLE_ID; } @Override @@ -80,7 +80,7 @@ public class SMTypeFilterButtons extends AbstractFilterButtons { @Override protected String createButtonId(final String name) { - return SPUIComponetIdProvider.SM_TYPE_FILTER_BTN_ID + name; + return SPUIComponentIdProvider.SM_TYPE_FILTER_BTN_ID + name; } @Override @@ -102,7 +102,7 @@ public class SMTypeFilterButtons extends AbstractFilterButtons { @Override protected String getButttonWrapperIdPrefix() { - return SPUIComponetIdProvider.UPLOAD_TYPE_BUTTON_PREFIX; + return SPUIComponentIdProvider.UPLOAD_TYPE_BUTTON_PREFIX; } @Override diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SMTypeFilterHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SMTypeFilterHeader.java index a12517b31..e1d71f359 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SMTypeFilterHeader.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SMTypeFilterHeader.java @@ -13,7 +13,7 @@ import javax.annotation.PostConstruct; import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent; import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; import org.eclipse.hawkbit.ui.common.filterlayout.AbstractFilterHeader; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.springframework.beans.factory.annotation.Autowired; @@ -86,7 +86,7 @@ public class SMTypeFilterHeader extends AbstractFilterHeader { @Override protected String getHideButtonId() { - return SPUIComponetIdProvider.SM_SHOW_FILTER_BUTTON_ID; + return SPUIComponentIdProvider.SM_SHOW_FILTER_BUTTON_ID; } @Override diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java index f82ce9ccf..ed2feef0a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java @@ -9,14 +9,18 @@ package org.eclipse.hawkbit.ui.artifacts.state; import java.io.Serializable; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.ui.artifacts.upload.UploadStatusObject; import org.eclipse.hawkbit.ui.common.ManagmentEntityState; import org.springframework.beans.factory.annotation.Autowired; @@ -49,15 +53,63 @@ public class ArtifactUploadState implements ManagmentEntityState, Serializ private Set selectedSoftwareModules = Collections.emptySet(); - private boolean swTypeFilterClosed = Boolean.FALSE; + private boolean swTypeFilterClosed; - private boolean swModuleTableMaximized = Boolean.FALSE; + private boolean swModuleTableMaximized; - private boolean artifactDetailsMaximized = Boolean.FALSE; + private boolean artifactDetailsMaximized; private final Set selectedDeleteSWModuleTypes = new HashSet<>(); - private boolean noDataAvilableSoftwareModule = Boolean.FALSE; + private boolean noDataAvilableSoftwareModule; + + private boolean statusPopupMinimized; + + private boolean uploadCompleted; + + private List uploadedFileStatusList = new ArrayList<>(); + + private final AtomicInteger numberOfFileUploadsExpected = new AtomicInteger(); + + private final AtomicInteger numberOfFilesActuallyUpload = new AtomicInteger(); + + private final AtomicInteger numberOfFileUploadsFailed = new AtomicInteger(); + + public AtomicInteger getNumberOfFileUploadsFailed() { + return numberOfFileUploadsFailed; + } + + public AtomicInteger getNumberOfFilesActuallyUpload() { + return numberOfFilesActuallyUpload; + } + + public AtomicInteger getNumberOfFileUploadsExpected() { + return numberOfFileUploadsExpected; + } + + public List getUploadedFileStatusList() { + return uploadedFileStatusList; + } + + public void setUploadedFileStatusList(final List uploadedFileStatusList) { + this.uploadedFileStatusList = uploadedFileStatusList; + } + + public boolean isUploadCompleted() { + return uploadCompleted; + } + + public void setUploadCompleted(final boolean uploadCompleted) { + this.uploadCompleted = uploadCompleted; + } + + public void setStatusPopupMinimized(final boolean statusPopupMinimized) { + this.statusPopupMinimized = statusPopupMinimized; + } + + public boolean isStatusPopupMinimized() { + return statusPopupMinimized; + } /** * Set software. diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadConfirmationwindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadConfirmationwindow.java index f009985f9..8455dea69 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadConfirmationwindow.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadConfirmationwindow.java @@ -28,7 +28,7 @@ import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleTiny; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.I18N; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; @@ -151,10 +151,10 @@ public class UploadConfirmationwindow implements Button.ClickListener { } private void createRequiredComponents() { - uploadBtn = SPUIComponentProvider.getButton(SPUIComponetIdProvider.UPLOAD_BUTTON, SPUILabelDefinitions.SUBMIT, + uploadBtn = SPUIComponentProvider.getButton(SPUIComponentIdProvider.UPLOAD_BUTTON, SPUILabelDefinitions.SUBMIT, SPUILabelDefinitions.SUBMIT, ValoTheme.BUTTON_PRIMARY, false, null, SPUIButtonStyleTiny.class); uploadBtn.addClickListener(this); - cancelBtn = SPUIComponentProvider.getButton(SPUIComponetIdProvider.UPLOAD_DISCARD_DETAILS_BUTTON, + cancelBtn = SPUIComponentProvider.getButton(SPUIComponentIdProvider.UPLOAD_DISCARD_DETAILS_BUTTON, SPUILabelDefinitions.DISCARD, SPUILabelDefinitions.DISCARD, null, false, null, SPUIButtonStyleTiny.class); cancelBtn.addClickListener(this); @@ -162,7 +162,7 @@ public class UploadConfirmationwindow implements Button.ClickListener { uploadDetailsTable = new Table(); uploadDetailsTable.addStyleName("artifact-table"); uploadDetailsTable.setSizeFull(); - uploadDetailsTable.setId(SPUIComponetIdProvider.UPLOAD_ARTIFACT_DETAILS_TABLE); + uploadDetailsTable.setId(SPUIComponentIdProvider.UPLOAD_ARTIFACT_DETAILS_TABLE); uploadDetailsTable.addStyleName(ValoTheme.TABLE_BORDERLESS); uploadDetailsTable.addStyleName(ValoTheme.TABLE_NO_VERTICAL_LINES); uploadDetailsTable.addStyleName(ValoTheme.TABLE_SMALL); @@ -238,23 +238,23 @@ public class UploadConfirmationwindow implements Button.ClickListener { newItem.getItemProperty(SW_MODULE_NAME).setValue(HawkbitCommonUtil.getFormatedLabel(swNameVersion)); newItem.getItemProperty(SIZE).setValue(customFile.getFileSize()); final Button deleteIcon = SPUIComponentProvider.getButton( - SPUIComponetIdProvider.UPLOAD_DELETE_ICON + "-" + itemId, "", SPUILabelDefinitions.DISCARD, + SPUIComponentIdProvider.UPLOAD_DELETE_ICON + "-" + itemId, "", SPUILabelDefinitions.DISCARD, ValoTheme.BUTTON_TINY + " " + "redicon", true, FontAwesome.TRASH_O, SPUIButtonStyleSmallNoBorder.class); deleteIcon.addClickListener(this); deleteIcon.setData(itemId); newItem.getItemProperty(ACTION).setValue(deleteIcon); - final TextField sha1 = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY, false, null, null, - true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); + final TextField sha1 = SPUIComponentProvider.getTextField(null, "", ValoTheme.TEXTFIELD_TINY, false, null, + null, true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); sha1.setId(swNameVersion + "/" + customFile.getFileName() + "/sha1"); - final TextField md5 = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY, false, null, null, - true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); + final TextField md5 = SPUIComponentProvider.getTextField(null, "", ValoTheme.TEXTFIELD_TINY, false, null, + null, true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); md5.setId(swNameVersion + "/" + customFile.getFileName() + "/md5"); - final TextField customFileName = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY, false, - null, null, true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); + final TextField customFileName = SPUIComponentProvider.getTextField(null, "", ValoTheme.TEXTFIELD_TINY, + false, null, null, true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); customFileName.setId(swNameVersion + "/" + customFile.getFileName() + "/customFileName"); newItem.getItemProperty(SHA1_CHECKSUM).setValue(sha1); newItem.getItemProperty(MD5_CHECKSUM).setValue(md5); @@ -265,8 +265,8 @@ public class UploadConfirmationwindow implements Button.ClickListener { private void addFileNameLayout(final Item newItem, final String baseSoftwareModuleNameVersion, final String customFileName, final String itemId) { final HorizontalLayout horizontalLayout = new HorizontalLayout(); - final TextField fileNameTextField = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY, false, - null, null, true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); + final TextField fileNameTextField = SPUIComponentProvider.getTextField(null, "", ValoTheme.TEXTFIELD_TINY, + false, null, null, true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); fileNameTextField.setId(baseSoftwareModuleNameVersion + "/" + customFileName + "/customFileName"); fileNameTextField.setData(baseSoftwareModuleNameVersion + "/" + customFileName); fileNameTextField.setValue(customFileName); @@ -541,16 +541,16 @@ public class UploadConfirmationwindow implements Button.ClickListener { @Override public void buttonClick(final ClickEvent event) { - if (event.getComponent().getId().equals(SPUIComponetIdProvider.UPLOAD_ARTIFACT_DETAILS_CLOSE)) { + if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_ARTIFACT_DETAILS_CLOSE)) { uploadConfrimationWindow.close(); - } else if (event.getComponent().getId().equals(SPUIComponetIdProvider.UPLOAD_DISCARD_DETAILS_BUTTON)) { - uploadLayout.clearFileList(); + } else if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_DISCARD_DETAILS_BUTTON)) { + uploadLayout.clearUploadedFileDetails(); uploadConfrimationWindow.close(); - } else if (event.getComponent().getId().equals(SPUIComponetIdProvider.UPLOAD_BUTTON)) { + } else if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_BUTTON)) { processArtifactUpload(); } - else if (event.getComponent().getId().startsWith(SPUIComponetIdProvider.UPLOAD_DELETE_ICON)) { + else if (event.getComponent().getId().startsWith(SPUIComponentIdProvider.UPLOAD_DELETE_ICON)) { final String itemId = ((Button) event.getComponent()).getData().toString(); final Item item = uploadDetailsTable.getItem(((Button) event.getComponent()).getData()); final Long swId = (Long) item.getItemProperty(BASE_SOFTWARE_ID).getValue(); @@ -568,10 +568,10 @@ public class UploadConfirmationwindow implements Button.ClickListener { uploadDetailsTable.removeItem(((Button) event.getComponent()).getData()); uploadLayout.getFileSelected().remove(customFile); - uploadLayout.updateActionCount(); + uploadLayout.updateUploadCounts(); if (uploadDetailsTable.getItemIds().isEmpty()) { - uploadLayout.clearFileList(); uploadConfrimationWindow.close(); + uploadLayout.clearUploadedFileDetails(); } } 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 77207bd50..78a6fd9a9 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 @@ -11,13 +11,21 @@ package org.eclipse.hawkbit.ui.artifacts.upload; import java.io.IOException; import java.io.OutputStream; +import javax.annotation.PreDestroy; + import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.ui.artifacts.state.CustomFile; +import org.eclipse.hawkbit.ui.artifacts.event.UploadFileStatus; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent.UploadStatusEventType; +import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; import org.eclipse.hawkbit.ui.utils.I18N; import org.eclipse.hawkbit.ui.utils.SpringContextHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.vaadin.spring.events.EventBus; +import org.vaadin.spring.events.EventScope; +import org.vaadin.spring.events.annotation.EventBusListenerMethod; import com.vaadin.server.StreamVariable; import com.vaadin.ui.Upload; @@ -49,28 +57,53 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene private final long fileSize; private final UploadLayout view; - private final UploadStatusInfoWindow infoWindow; private final long maxSize; private final Upload upload; private volatile String fileName = null; private volatile String mimeType = null; - private volatile boolean interrupted = false; + private volatile boolean streamingInterrupted = false; + private volatile boolean uploadInterrupted = false; + private volatile boolean aborted = false; + private String failureReason; private final I18N i18n; + private transient EventBus.SessionEventBus eventBus; + private final SoftwareModule selectedSw; + private SoftwareModule selectedSwForUpload; + private ArtifactUploadState artifactUploadState; - UploadHandler(final String fileName, final long fileSize, final UploadLayout view, - final UploadStatusInfoWindow infoWindow, final long maxSize, final Upload upload, final String mimeType) { + UploadHandler(final String fileName, final long fileSize, final UploadLayout view, final long maxSize, + final Upload upload, final String mimeType, SoftwareModule selectedSw) { super(); + this.aborted = false; this.fileName = fileName; this.fileSize = fileSize; this.view = view; - this.infoWindow = infoWindow; this.maxSize = maxSize; this.upload = upload; this.mimeType = mimeType; + this.selectedSw = selectedSw; this.i18n = SpringContextHelper.getBean(I18N.class); + this.eventBus = SpringContextHelper.getBean(EventBus.SessionEventBus.class); + this.artifactUploadState = SpringContextHelper.getBean(ArtifactUploadState.class); + eventBus.subscribe(this); + } + @PreDestroy + void destroy() { + /* + * It's good manners to do this, even though vaadin-spring will + * automatically unsubscribe when this UI is garbage collected. + */ + eventBus.unsubscribe(this); + } + + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvent(final UploadStatusEventType event) { + if (event == UploadStatusEventType.ABORT_UPLOAD) { + aborted = true; + } } /** @@ -81,11 +114,13 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public final OutputStream getOutputStream() { try { - return view.saveUploadedFileDetails(fileName, fileSize, mimeType); + streamingInterrupted = false; + failureReason = null; + return view.saveUploadedFileDetails(fileName, fileSize, mimeType, selectedSw); } catch (final ArtifactUploadFailedException e) { LOG.error("Atifact upload failed {} ", e); failureReason = e.getMessage(); - interrupted = true; + streamingInterrupted = true; return new NullOutputStream(); } } @@ -98,23 +133,22 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene */ @Override public OutputStream receiveUpload(final String fileName, final String mimeType) { + aborted = false; + failureReason = null; this.fileName = fileName; this.mimeType = mimeType; // reset has directory flag before upload view.setHasDirectory(false); try { - if (view.checkIfSoftwareModuleIsSelected()) { - if (view.checkForDuplicate(fileName)) { - view.showDuplicateMessage(); - } else { - view.increaseNumberOfFileUploadsExpected(); - return view.saveUploadedFileDetails(fileName, 0, mimeType); - } + if (view.checkIfSoftwareModuleIsSelected() && !view.checkForDuplicate(fileName, selectedSwForUpload)) { + view.increaseNumberOfFileUploadsExpected(); + return view.saveUploadedFileDetails(fileName, 0, mimeType, selectedSwForUpload); } } catch (final ArtifactUploadFailedException e) { LOG.error("Atifact upload failed {} ", e); failureReason = e.getMessage(); upload.interruptUpload(); + uploadInterrupted = true; } // if final validation fails ,final no upload ,return NullOutputStream return new NullOutputStream(); @@ -129,13 +163,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public void uploadSucceeded(final SucceededEvent event) { LOG.debug("Streaming finished for file :{}", event.getFilename()); - view.updateFileSize(event.getFilename(), event.getLength()); - - // recorded that we now one more uploaded - view.increaseNumberOfFilesActuallyUpload(); - - // inform upload status window - infoWindow.uploadSucceeded(event.getFilename()); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_SUCCESSFUL, new UploadFileStatus( + event.getFilename(), 0, event.getLength(), selectedSwForUpload))); } /** @@ -148,20 +177,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public void streamingFinished(final StreamingEndEvent event) { LOG.debug("Streaming finished for file :{}", event.getFileName()); - // record that we now one more uploaded - view.increaseNumberOfFilesActuallyUpload(); - - // inform upload status window - infoWindow.uploadSucceeded(event.getFileName()); - - // check if we are finished - if (view.enableProcessBtn()) { - infoWindow.uploadSessionFinished(); - } - view.updateActionCount(); - - // display the duplicate message after streaming all files - view.displayDuplicateValidationMessage(); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STREAMING_FINISHED, + new UploadFileStatus(event.getFileName(), 0, event.getContentLength(), selectedSw))); } /** @@ -173,12 +190,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public void uploadFinished(final FinishedEvent event) { LOG.debug("Upload finished for file :{}", event.getFilename()); - // check if we are finished - if (view.enableProcessBtn()) { - infoWindow.uploadSessionFinished(); - } - view.updateActionCount(); - + eventBus.publish(this, + new UploadStatusEvent(UploadStatusEventType.UPLOAD_FINISHED, new UploadFileStatus(event.getFilename()))); } /** @@ -189,7 +202,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public void streamingStarted(final StreamingStartEvent event) { LOG.debug("Streaming started for file :{}", fileName); - infoWindow.uploadStarted(fileName); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STARTED, new UploadFileStatus( + fileName, 0, 0, selectedSw))); } /** @@ -199,14 +213,24 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene */ @Override public void uploadStarted(final StartedEvent event) { - // single file session - if (view.isSoftwareModuleSelected() && !view.checkIfFileIsDuplicate(event.getFilename())) { - infoWindow.uploadSessionStarted(); - LOG.debug("Upload started for file :{}", event.getFilename()); - infoWindow.uploadStarted(event.getFilename()); - } else { + uploadInterrupted = false; + selectedSwForUpload = artifactUploadState.getSelectedBaseSoftwareModule().isPresent() ? artifactUploadState + .getSelectedBaseSoftwareModule().get() : null; + + if (view.isSoftwareModuleSelected()) { + // single file session + if (!view.checkIfFileIsDuplicate(event.getFilename(), selectedSwForUpload)) { + LOG.debug("Upload started for file :{}", event.getFilename()); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STARTED, + new UploadFileStatus(event.getFilename(), 0, 0, selectedSwForUpload))); + } + } + else { failureReason = i18n.get("message.upload.failed"); upload.interruptUpload(); + // actual interrupt will happen a bit late so setting the below + // flag + uploadInterrupted = true; } } @@ -227,21 +251,25 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene */ @Override public void updateProgress(final long readBytes, final long contentLength) { - if (readBytes > maxSize || contentLength > maxSize) { - LOG.error("User tried to upload more than was allowed ({}).", maxSize); - view.decreaseNumberOfFileUploadsExpected(); - final SoftwareModule sw = view.getSoftwareModuleSelected(); - view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion())); - view.updateActionCount(); - failureReason = i18n.get("message.uploadedfile.size.exceeded", maxSize); - infoWindow.uploadFailed(fileName, failureReason); - upload.interruptUpload(); - interrupted = true; - return; + // Update progress is called event after upload interrupted in + // uploadStarted method + if (!uploadInterrupted) { + if (aborted) { + LOG.info("User aborted file upload for file : {}", fileName); + failureReason = i18n.get("message.uploadedfile.aborted"); + interruptFileUpload(); + return; + } + if (readBytes > maxSize || contentLength > maxSize) { + LOG.error("User tried to upload more than was allowed ({}).", maxSize); + failureReason = i18n.get("message.uploadedfile.size.exceeded", maxSize); + interruptFileUpload(); + return; + } + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_IN_PROGRESS, + new UploadFileStatus(fileName, readBytes, contentLength, selectedSwForUpload))); + LOG.info("Update progress - {} : {}", fileName, (double) readBytes / (double) contentLength); } - - infoWindow.updateProgress(fileName, readBytes, contentLength); - LOG.info("Update progress - {} : {}", fileName, (double) readBytes / (double) contentLength); } /** @@ -251,19 +279,20 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene */ @Override public void onProgress(final StreamingProgressEvent event) { - if (event.getBytesReceived() > maxSize || event.getContentLength() > maxSize) { - LOG.error("User tried to upload more than was allowed ({}).", maxSize); - view.decreaseNumberOfFileUploadsExpected(); - final SoftwareModule sw = view.getSoftwareModuleSelected(); - view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion())); - view.updateActionCount(); - failureReason = i18n.get("message.uploadedfile.size.exceeded", maxSize); - infoWindow.uploadFailed(event.getFileName(), failureReason); - interrupted = true; + if (aborted) { + LOG.info("User aborted the upload for file : {}", event.getFileName()); + failureReason = i18n.get("message.uploadedfile.aborted"); + interruptFileStreaming(); return; } - - infoWindow.updateProgress(event.getFileName(), event.getBytesReceived(), event.getContentLength()); + if (event.getBytesReceived() > maxSize || event.getContentLength() > maxSize) { + LOG.error("User tried to upload more than was allowed ({}).", maxSize); + failureReason = i18n.get("message.uploadedfile.size.exceeded", maxSize); + interruptFileStreaming(); + return; + } + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_IN_PROGRESS, new UploadFileStatus( + fileName, event.getBytesReceived(), event.getContentLength(), selectedSw))); // Logging to solve sonar issue LOG.trace("Streaming in progress for file :{}", event.getFileName()); } @@ -276,19 +305,16 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene */ @Override public void streamingFailed(final StreamingErrorEvent event) { - LOG.info("Streaming failed for file :{}", event.getFileName()); - view.decreaseNumberOfFileUploadsExpected(); - final SoftwareModule sw = view.getSoftwareModuleSelected(); - view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion())); - view.updateActionCount(); - infoWindow.uploadFailed(event.getFileName(), failureReason); - // check if we are finished - if (view.enableProcessBtn()) { - infoWindow.uploadSessionFinished(); + if (failureReason == null) { + failureReason = event.getException().getMessage(); } - view.displayDuplicateValidationMessage(); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STREAMING_FAILED, + new UploadFileStatus(fileName, failureReason, selectedSw))); - LOG.info("Streaming failed due to :{}", event.getException()); + if (!aborted) { + LOG.info("Streaming failed for file :{}", event.getFileName()); + LOG.info("Streaming failed due to :{}", event.getException()); + } } /** @@ -298,20 +324,21 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene */ @Override public void uploadFailed(final FailedEvent event) { - LOG.info("Upload failed for file :{}", event.getFilename()); - view.decreaseNumberOfFileUploadsExpected(); /** - * If upload interrupted because of duplicate file,do not remove the - * file already in upload list - **/ - if (!view.getDuplicateFileNamesList().isEmpty()) { - final SoftwareModule sw = view.getSoftwareModuleSelected(); - view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion())); + * If upload failed due to no selected software UPLOAD_FAILED event need + * not be published. + */ + if (selectedSwForUpload != null) { + if (failureReason == null) { + failureReason = event.getReason().getMessage(); + } + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_FAILED, new UploadFileStatus( + fileName, failureReason, selectedSwForUpload))); + if (!aborted) { + LOG.info("Upload failed for file :{}", event.getFilename()); + LOG.info("Upload failed for file :{}", event.getReason()); + } } - view.updateActionCount(); - infoWindow.uploadFailed(event.getFilename(), failureReason); - LOG.info("Upload failed for file :{}", event.getReason()); - } /** @@ -319,7 +346,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene */ @Override public boolean isInterrupted() { - return interrupted; + return streamingInterrupted; } private static class NullOutputStream extends OutputStream { @@ -339,7 +366,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + (fileName == null ? 0 : fileName.hashCode()); + result = prime * result + ((fileName == null) ? 0 : fileName.hashCode()); return result; } @@ -348,16 +375,30 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene if (this == obj) { return true; } - if (!(obj instanceof UploadHandler)) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { return false; } final UploadHandler other = (UploadHandler) obj; - if (fileName == null && other.fileName != null) { - return false; + if (fileName == null) { + if (other.fileName != null) { + return false; + } } else if (!fileName.equals(other.fileName)) { return false; } return true; } + private void interruptFileStreaming() { + streamingInterrupted = true; + } + + private void interruptFileUpload() { + upload.interruptUpload(); + uploadInterrupted = true; + } + } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadLayout.java index 7376cce13..af02e917b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadLayout.java @@ -16,7 +16,6 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -26,13 +25,15 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent; import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent.SoftwareModuleEventType; import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent.UploadStatusEventType; import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; import org.eclipse.hawkbit.ui.artifacts.state.CustomFile; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmall; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.I18N; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; @@ -97,10 +98,6 @@ public class UploadLayout extends VerticalLayout { @Autowired private transient SPInfo spInfo; - private final AtomicInteger numberOfFileUploadsExpected = new AtomicInteger(); - - private final AtomicInteger numberOfFilesActuallyUpload = new AtomicInteger(); - private final List duplicateFileNamesList = new ArrayList<>(); private Button processBtn; @@ -119,6 +116,8 @@ public class UploadLayout extends VerticalLayout { private Boolean hasDirectory = Boolean.FALSE; + private Button uploadStatusButton; + /** * Initialize the upload layout. */ @@ -126,13 +125,52 @@ public class UploadLayout extends VerticalLayout { void init() { createComponents(); buildLayout(); - updateActionCount(); + restoreState(); eventBus.subscribe(this); ui = UI.getCurrent(); } - private void createComponents() { + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvent(final UploadArtifactUIEvent event) { + if (event == UploadArtifactUIEvent.DELETED_ALL_SOFWARE) { + ui.access(() -> updateActionCount()); + } else if (event == UploadArtifactUIEvent.MINIMIZED_STATUS_POPUP) { + ui.access(() -> showUploadStatusButton()); + } else if (event == UploadArtifactUIEvent.MAXIMIZED_STATUS_POPUP) { + ui.access(() -> maximizeStatusPopup()); + } else if (event == UploadArtifactUIEvent.ARTIFACT_RESULT_POPUP_CLOSED) { + ui.access(() -> closeUploadStatusPopup()); + } + } + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvent(final UploadStatusEvent event) { + if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STARTED) { + ui.access(() -> onStartOfUpload()); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_FAILED) { + ui.access(() -> onUploadFailure(event)); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_FINISHED) { + ui.access(() -> onUploadCompletion()); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_SUCCESSFUL) { + ui.access(() -> onUploadSuccess(event)); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FAILED) { + ui.access(() -> onUploadStreamingFailure(event)); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FINISHED) { + ui.access(() -> onUploadStreamingSuccess()); + } + } + + @PreDestroy + void destroy() { + /* + * It's good manners to do this, even though vaadin-spring will + * automatically unsubscribe when this UI is garbage collected. + */ + eventBus.unsubscribe(this); + } + + private void createComponents() { + createUploadStatusButton(); createProcessButton(); createDiscardBtn(); } @@ -140,8 +178,8 @@ public class UploadLayout extends VerticalLayout { private void buildLayout() { final Upload upload = new Upload(); - final UploadHandler uploadHandler = new UploadHandler(null, 0, this, uploadInfoWindow, - spInfo.getMaxArtifactFileSize(), upload, null); + final UploadHandler uploadHandler = new UploadHandler(null, 0, this, spInfo.getMaxArtifactFileSize(), upload, + null, null); upload.setButtonCaption(i18n.get("upload.file")); upload.setImmediate(true); upload.setReceiver(uploadHandler); @@ -154,12 +192,15 @@ public class UploadLayout extends VerticalLayout { fileUploadLayout = new HorizontalLayout(); fileUploadLayout.setSpacing(true); + fileUploadLayout.addStyleName(SPUIStyleDefinitions.FOOTER_LAYOUT); fileUploadLayout.addComponent(upload); fileUploadLayout.setComponentAlignment(upload, Alignment.MIDDLE_LEFT); fileUploadLayout.addComponent(processBtn); fileUploadLayout.setComponentAlignment(processBtn, Alignment.MIDDLE_RIGHT); fileUploadLayout.addComponent(discardBtn); fileUploadLayout.setComponentAlignment(discardBtn, Alignment.MIDDLE_RIGHT); + fileUploadLayout.addComponent(uploadStatusButton); + fileUploadLayout.setComponentAlignment(uploadStatusButton, Alignment.MIDDLE_RIGHT); setMargin(false); /* create drag-drop wrapper for drop area */ @@ -167,7 +208,25 @@ public class UploadLayout extends VerticalLayout { dropAreaWrapper.setDropHandler(new DropAreahandler()); setSizeFull(); setSpacing(true); + } + private void restoreState() { + updateActionCount(); + + if (!artifactUploadState.getFileSelected().isEmpty() && artifactUploadState.isUploadCompleted()) { + processBtn.setEnabled(true); + } + if (artifactUploadState.isStatusPopupMinimized()) { + showUploadStatusButton(); + if (artifactUploadState.isUploadCompleted()) { + setUploadStatusButtonIconToFinished(); + } + } + if (artifactUploadState.isUploadCompleted()) { + artifactUploadState.getNumberOfFilesActuallyUpload().set(0); + artifactUploadState.getNumberOfFileUploadsExpected().set(0); + artifactUploadState.getNumberOfFileUploadsFailed().set(0); + } } public DragAndDropWrapper getDropAreaWrapper() { @@ -187,15 +246,16 @@ public class UploadLayout extends VerticalLayout { public void drop(final DragAndDropEvent event) { if (validate(event)) { final Html5File[] files = ((WrapperTransferable) event.getTransferable()).getFiles(); + // selected software module at the time of file drop is + // considered for upload + SoftwareModule selectedSw = artifactUploadState.getSelectedBaseSoftwareModule().get(); // reset the flag hasDirectory = Boolean.FALSE; for (final Html5File file : files) { - processFile(file); + processFile(file, selectedSw); } - if (numberOfFileUploadsExpected.get() > 0) { + if (artifactUploadState.getNumberOfFileUploadsExpected().get() > 0) { processBtn.setEnabled(false); - // reset before we start - uploadInfoWindow.uploadSessionStarted(); } else { // If the upload is not started, it signifies all // dropped files as either duplicate or directory.So @@ -205,20 +265,20 @@ public class UploadLayout extends VerticalLayout { } } - private void processFile(final Html5File file) { + private void processFile(final Html5File file, SoftwareModule selectedSw) { if (!isDirectory(file)) { - if (!checkForDuplicate(file.getFileName())) { - numberOfFileUploadsExpected.incrementAndGet(); - file.setStreamVariable(createStreamVariable(file)); + if (!checkForDuplicate(file.getFileName(), selectedSw)) { + artifactUploadState.getNumberOfFileUploadsExpected().incrementAndGet(); + file.setStreamVariable(createStreamVariable(file, selectedSw)); } } else { hasDirectory = Boolean.TRUE; } } - private StreamVariable createStreamVariable(final Html5File file) { - return new UploadHandler(file.getFileName(), file.getFileSize(), UploadLayout.this, uploadInfoWindow, - spInfo.getMaxArtifactFileSize(), null, file.getType()); + private StreamVariable createStreamVariable(final Html5File file, SoftwareModule selectedSw) { + return new UploadHandler(file.getFileName(), file.getFileSize(), UploadLayout.this, + spInfo.getMaxArtifactFileSize(), null, file.getType(), selectedSw); } private boolean isDirectory(final Html5File file) { @@ -263,44 +323,33 @@ public class UploadLayout extends VerticalLayout { } private void createProcessButton() { - processBtn = SPUIComponentProvider.getButton(SPUIComponetIdProvider.UPLOAD_PROCESS_BUTTON, + processBtn = SPUIComponentProvider.getButton(SPUIComponentIdProvider.UPLOAD_PROCESS_BUTTON, SPUILabelDefinitions.PROCESS, SPUILabelDefinitions.PROCESS, null, false, null, SPUIButtonStyleSmall.class); processBtn.setIcon(FontAwesome.BELL); processBtn.addStyleName(SPUIStyleDefinitions.ACTION_BUTTON); - processBtn.addClickListener(event -> displayConfirmWindow(event)); + processBtn.addClickListener(this::displayConfirmWindow); processBtn.setHtmlContentAllowed(true); - if (artifactUploadState.getFileSelected().isEmpty()) { - processBtn.setEnabled(false); - } + processBtn.setEnabled(false); } private void createDiscardBtn() { - discardBtn = SPUIComponentProvider.getButton(SPUIComponetIdProvider.UPLOAD_DISCARD_BUTTON, + discardBtn = SPUIComponentProvider.getButton(SPUIComponentIdProvider.UPLOAD_DISCARD_BUTTON, SPUILabelDefinitions.DISCARD, SPUILabelDefinitions.DISCARD, null, false, null, SPUIButtonStyleSmall.class); discardBtn.setIcon(FontAwesome.TRASH_O); discardBtn.addStyleName(SPUIStyleDefinitions.ACTION_BUTTON); - discardBtn.addClickListener(event -> discardUploadData(event)); + discardBtn.addClickListener(this::discardUploadData); } - boolean checkForDuplicate(final String filename) { - final Boolean isDuplicate = checkIfFileIsDuplicate(filename); + boolean checkForDuplicate(final String filename, final SoftwareModule selectedSw) { + final Boolean isDuplicate = checkIfFileIsDuplicate(filename, selectedSw); if (isDuplicate) { getDuplicateFileNamesList().add(filename); } return isDuplicate; } - @EventBusListenerMethod(scope = EventScope.SESSION) - void toggleProcessButton(final UploadArtifactUIEvent event) { - if (event == UploadArtifactUIEvent.ENABLE_PROCESS_BUTTON) { - processBtn.setEnabled(true); - } else if (event == UploadArtifactUIEvent.DISABLE_PROCESS_BUTTON) { - processBtn.setEnabled(false); - } - } - /** * Save uploaded file details. * @@ -312,29 +361,29 @@ public class UploadLayout extends VerticalLayout { * file size * @param mimeType * the mimeType of the file + * @param selectedSw * @throws IOException * in case of upload errors */ - OutputStream saveUploadedFileDetails(final String name, final long size, final String mimeType) { + OutputStream saveUploadedFileDetails(final String name, final long size, final String mimeType, + SoftwareModule selectedSw) { File tempFile = null; try { tempFile = File.createTempFile("spUiArtifactUpload", null); final OutputStream out = new FileOutputStream(tempFile); - final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); + final String currentBaseSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion(selectedSw.getName(), + selectedSw.getVersion()); - final String currentBaseSoftwareModuleKey = HawkbitCommonUtil - .getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); - - final CustomFile customFile = new CustomFile(name, size, tempFile.getAbsolutePath(), - selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion(), mimeType); + final CustomFile customFile = new CustomFile(name, size, tempFile.getAbsolutePath(), selectedSw.getName(), + selectedSw.getVersion(), mimeType); artifactUploadState.getFileSelected().add(customFile); processBtn.setEnabled(false); if (!artifactUploadState.getBaseSwModuleList().keySet().contains(currentBaseSoftwareModuleKey)) { - artifactUploadState.getBaseSwModuleList().put(currentBaseSoftwareModuleKey, selectedSoftwareModule); + artifactUploadState.getBaseSwModuleList().put(currentBaseSoftwareModuleKey, selectedSw); } return out; } catch (final FileNotFoundException e) { @@ -344,6 +393,7 @@ public class UploadLayout extends VerticalLayout { LOG.error("Upload failed {}", e); throw new ArtifactUploadFailedException(i18n.get("message.upload.failed")); } + } Boolean validate(final DragAndDropEvent event) { @@ -378,13 +428,6 @@ public class UploadLayout extends VerticalLayout { return true; } - SoftwareModule getSoftwareModuleSelected() { - if (artifactUploadState.getSelectedBaseSoftwareModule().isPresent()) { - return artifactUploadState.getSelectedBaseSoftwareModule().get(); - } - return null; - } - Boolean isSoftwareModuleSelected() { if (!artifactUploadState.getSelectedBaseSwModuleId().isPresent()) { return false; @@ -400,11 +443,10 @@ public class UploadLayout extends VerticalLayout { * file name * @return Boolean */ - public Boolean checkIfFileIsDuplicate(final String name) { + public Boolean checkIfFileIsDuplicate(final String name, final SoftwareModule selectedSoftwareModule) { Boolean isDuplicate = false; - final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); - final String currentBaseSoftwareModuleKey = HawkbitCommonUtil - .getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); + final String currentBaseSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion( + selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); for (final CustomFile customFile : artifactUploadState.getFileSelected()) { final String fileSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion( @@ -418,7 +460,7 @@ public class UploadLayout extends VerticalLayout { } void decreaseNumberOfFileUploadsExpected() { - numberOfFileUploadsExpected.decrementAndGet(); + artifactUploadState.getNumberOfFileUploadsExpected().decrementAndGet(); } List getDuplicateFileNamesList() { @@ -439,8 +481,10 @@ public class UploadLayout extends VerticalLayout { void displayDuplicateValidationMessage() { // check if streaming of all dropped files are completed - if (numberOfFilesActuallyUpload.intValue() == numberOfFileUploadsExpected.intValue()) { + if (artifactUploadState.getNumberOfFilesActuallyUpload().intValue() == artifactUploadState + .getNumberOfFileUploadsExpected().intValue()) { displayCompositeMessage(); + duplicateFileNamesList.clear(); } } @@ -454,7 +498,6 @@ public class UploadLayout extends VerticalLayout { } else if (duplicateFileNamesList.size() > 1) { message.append(i18n.get("message.no.duplicateFiles")); } - duplicateFileNamesList.clear(); } return message.toString(); } @@ -464,13 +507,12 @@ public class UploadLayout extends VerticalLayout { } void increaseNumberOfFileUploadsExpected() { - numberOfFileUploadsExpected.incrementAndGet(); + artifactUploadState.getNumberOfFileUploadsExpected().incrementAndGet(); } - void updateFileSize(final String name, final long size) { - final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); - final String currentBaseSoftwareModuleKey = HawkbitCommonUtil - .getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); + void updateFileSize(final String name, final long size, SoftwareModule selectedSoftwareModule) { + final String currentBaseSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion( + selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); for (final CustomFile customFile : artifactUploadState.getFileSelected()) { final String fileSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion( @@ -483,17 +525,22 @@ public class UploadLayout extends VerticalLayout { } void increaseNumberOfFilesActuallyUpload() { - numberOfFilesActuallyUpload.incrementAndGet(); + artifactUploadState.getNumberOfFilesActuallyUpload().incrementAndGet(); + } + + void increaseNumberOfFileUploadsFailed() { + artifactUploadState.getNumberOfFileUploadsFailed().incrementAndGet(); } /** * Enable process button once upload is completed. */ boolean enableProcessBtn() { - if (numberOfFilesActuallyUpload.intValue() >= numberOfFileUploadsExpected.intValue()) { + if (artifactUploadState.getNumberOfFilesActuallyUpload().intValue() >= artifactUploadState + .getNumberOfFileUploadsExpected().intValue() && !getFileSelected().isEmpty()) { processBtn.setEnabled(true); - numberOfFileUploadsExpected.set(0); - numberOfFilesActuallyUpload.set(0); + artifactUploadState.getNumberOfFilesActuallyUpload().set(0); + artifactUploadState.getNumberOfFileUploadsExpected().set(0); return true; } return false; @@ -507,13 +554,23 @@ public class UploadLayout extends VerticalLayout { if (event.getButton().equals(discardBtn)) { if (artifactUploadState.getFileSelected().isEmpty()) { uiNotification.displayValidationError(i18n.get("message.error.noFileSelected")); - } else { - clearFileList(); + clearUploadedFileDetails(); } } } + protected void clearUploadedFileDetails() { + clearFileList(); + closeUploadStatusPopup(); + } + + private void closeUploadStatusPopup() { + uploadInfoWindow.clearWindow(); + hideUploadStatusButton(); + artifactUploadState.setStatusPopupMinimized(false); + } + /** * Clear details. */ @@ -529,19 +586,20 @@ public class UploadLayout extends VerticalLayout { processBtn.setCaption(SPUILabelDefinitions.PROCESS); /* disable when there is no files to upload. */ processBtn.setEnabled(false); - numberOfFileUploadsExpected.set(0); - numberOfFilesActuallyUpload.set(0); + artifactUploadState.getNumberOfFilesActuallyUpload().set(0); + artifactUploadState.getNumberOfFileUploadsExpected().set(0); + artifactUploadState.getNumberOfFileUploadsFailed().set(0); duplicateFileNamesList.clear(); } private void setConfirmationPopupHeightWidth(final float newWidth, final float newHeight) { if (currentUploadConfirmationwindow != null) { - currentUploadConfirmationwindow.getUploadArtifactDetails().setWidth(HawkbitCommonUtil - .getArtifactUploadPopupWidth(newWidth, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), - Unit.PIXELS); - currentUploadConfirmationwindow.getUploadDetailsTable().setHeight(HawkbitCommonUtil - .getArtifactUploadPopupHeight(newHeight, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), - Unit.PIXELS); + currentUploadConfirmationwindow.getUploadArtifactDetails().setWidth( + HawkbitCommonUtil.getArtifactUploadPopupWidth(newWidth, + SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), Unit.PIXELS); + currentUploadConfirmationwindow.getUploadDetailsTable().setHeight( + HawkbitCommonUtil.getArtifactUploadPopupHeight(newHeight, + SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), Unit.PIXELS); } } @@ -558,22 +616,24 @@ public class UploadLayout extends VerticalLayout { && currentUploadConfirmationwindow.getCurrentUploadResultWindow() != null) { final UploadResultWindow uploadResultWindow = currentUploadConfirmationwindow .getCurrentUploadResultWindow(); - uploadResultWindow.getUploadResultsWindow().setWidth(HawkbitCommonUtil.getArtifactUploadPopupWidth(newWidth, - SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), Unit.PIXELS); - uploadResultWindow.getUploadResultTable().setHeight(HawkbitCommonUtil.getArtifactUploadPopupHeight( - newHeight, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), Unit.PIXELS); + uploadResultWindow.getUploadResultsWindow().setWidth( + HawkbitCommonUtil.getArtifactUploadPopupWidth(newWidth, + SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), Unit.PIXELS); + uploadResultWindow.getUploadResultTable().setHeight( + HawkbitCommonUtil.getArtifactUploadPopupHeight(newHeight, + SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), Unit.PIXELS); } } private void displayConfirmWindow(final Button.ClickEvent event) { - if (event.getComponent().getId().equals(SPUIComponetIdProvider.UPLOAD_PROCESS_BUTTON)) { + if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_PROCESS_BUTTON)) { if (artifactUploadState.getFileSelected().isEmpty()) { uiNotification.displayValidationError(i18n.get("message.error.noFileSelected")); } else { currentUploadConfirmationwindow = new UploadConfirmationwindow(this, artifactUploadState); UI.getCurrent().addWindow(currentUploadConfirmationwindow.getUploadConfrimationWindow()); - setConfirmationPopupHeightWidth(Page.getCurrent().getBrowserWindowWidth(), - Page.getCurrent().getBrowserWindowHeight()); + setConfirmationPopupHeightWidth(Page.getCurrent().getBrowserWindowWidth(), Page.getCurrent() + .getBrowserWindowHeight()); } } } @@ -599,25 +659,101 @@ public class UploadLayout extends VerticalLayout { /** * @return */ - VerticalLayout getDropAreaLayout() { return dropAreaLayout; } - @EventBusListenerMethod(scope = EventScope.SESSION) - void onEvent(final UploadArtifactUIEvent event) { - if (event == UploadArtifactUIEvent.DELETED_ALL_SOFWARE) { - ui.access(() -> updateActionCount()); + private void onStartOfUpload() { + setUploadStatusButtonIconToInProgress(); + if (artifactUploadState.isStatusPopupMinimized()) { + updateStatusButtonCount(); } } - @PreDestroy - void destroy() { - /* - * It's good manners to do this, even though vaadin-spring will - * automatically unsubscribe when this UI is garbage collected. - */ - eventBus.unsubscribe(this); + private void onUploadStreamingSuccess() { + increaseNumberOfFilesActuallyUpload(); + updateUploadCounts(); + enableProcessBtn(); + if (isUploadComplete()) { + uploadInfoWindow.uploadSessionFinished(); + setUploadStatusButtonIconToFinished(); + } + // display the duplicate message after streaming all files + displayDuplicateValidationMessage(); + } + + private void onUploadStreamingFailure(UploadStatusEvent event) { + /** + * If upload interrupted because of duplicate file,do not remove the + * file already in upload list + **/ + if (getDuplicateFileNamesList().isEmpty() + || !getDuplicateFileNamesList().contains(event.getUploadStatus().getFileName())) { + final SoftwareModule sw = event.getUploadStatus().getSoftwareModule(); + if (sw != null) { + getFileSelected().remove( + new CustomFile(event.getUploadStatus().getFileName(), sw.getName(), sw.getVersion())); + } + // failed reason to be updated only if there is error other than + // duplicate file error + uploadInfoWindow.uploadFailed(event.getUploadStatus().getFileName(), event.getUploadStatus() + .getFailureReason(), event.getUploadStatus().getSoftwareModule()); + increaseNumberOfFileUploadsFailed(); + } + decreaseNumberOfFileUploadsExpected(); + updateUploadCounts(); + enableProcessBtn(); + // check if we are finished + if (isUploadComplete()) { + uploadInfoWindow.uploadSessionFinished(); + setUploadStatusButtonIconToFinished(); + } + displayDuplicateValidationMessage(); + } + + private void onUploadSuccess(UploadStatusEvent event) { + updateFileSize(event.getUploadStatus().getFileName(), event.getUploadStatus().getContentLength(), event + .getUploadStatus().getSoftwareModule()); + // recorded that we now one more uploaded + increaseNumberOfFilesActuallyUpload(); + } + + private void onUploadCompletion() { + // check if we are finished + if (isUploadComplete()) { + uploadInfoWindow.uploadSessionFinished(); + setUploadStatusButtonIconToFinished(); + displayDuplicateValidationMessage(); + } + updateUploadCounts(); + enableProcessBtn(); + } + + private boolean isUploadComplete() { + int uploadedCount = artifactUploadState.getNumberOfFilesActuallyUpload().intValue(); + int expectedUploadsCount = artifactUploadState.getNumberOfFileUploadsExpected().intValue(); + return uploadedCount == expectedUploadsCount; + } + + private void onUploadFailure(final UploadStatusEvent event) { + /** + * If upload interrupted because of duplicate file,do not remove the + * file already in upload list + **/ + if (getDuplicateFileNamesList().isEmpty() + || !getDuplicateFileNamesList().contains(event.getUploadStatus().getFileName())) { + final SoftwareModule sw = event.getUploadStatus().getSoftwareModule(); + if (sw != null) { + getFileSelected().remove( + new CustomFile(event.getUploadStatus().getFileName(), sw.getName(), sw.getVersion())); + } + // failed reason to be updated only if there is error other than + // duplicate file error + uploadInfoWindow.uploadFailed(event.getUploadStatus().getFileName(), event.getUploadStatus() + .getFailureReason(), event.getUploadStatus().getSoftwareModule()); + increaseNumberOfFileUploadsFailed(); + decreaseNumberOfFileUploadsExpected(); + } } /** @@ -637,8 +773,8 @@ public class UploadLayout extends VerticalLayout { * @param selectedBaseSoftwareModule */ public void refreshArtifactDetailsLayout(final SoftwareModule selectedBaseSoftwareModule) { - eventBus.publish(this, - new SoftwareModuleEvent(SoftwareModuleEventType.ARTIFACTS_CHANGED, selectedBaseSoftwareModule)); + eventBus.publish(this, new SoftwareModuleEvent(SoftwareModuleEventType.ARTIFACTS_CHANGED, + selectedBaseSoftwareModule)); } /** @@ -655,4 +791,79 @@ public class UploadLayout extends VerticalLayout { public void setHasDirectory(final Boolean hasDirectory) { this.hasDirectory = hasDirectory; } + + private void createUploadStatusButton() { + uploadStatusButton = SPUIComponentProvider.getButton(SPUIComponentIdProvider.UPLOAD_STATUS_BUTTON, "", "", "", + false, null, SPUIButtonStyleSmall.class); + uploadStatusButton.setStyleName(SPUIStyleDefinitions.ACTION_BUTTON); + uploadStatusButton.addStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE); + uploadStatusButton.setWidth("100px"); + uploadStatusButton.setHtmlContentAllowed(true); + uploadStatusButton.addClickListener(event -> onClickOfUploadStatusButton()); + uploadStatusButton.setVisible(false); + } + + void updateStatusButtonCount() { + int uploadsPending = artifactUploadState.getNumberOfFileUploadsExpected().get() + - artifactUploadState.getNumberOfFilesActuallyUpload().get(); + int uploadsFailed = artifactUploadState.getNumberOfFileUploadsFailed().get(); + StringBuilder builder = new StringBuilder(""); + if (uploadsFailed != 0) { + if (uploadsPending != 0) { + builder.append("

" + uploadsFailed + "
"); + } else { + builder.append("
" + uploadsFailed + "
"); + } + } + if (uploadsPending != 0) { + builder.append("
" + uploadsPending + "
"); + } + uploadStatusButton.setCaption(builder.toString()); + } + + private void onClickOfUploadStatusButton() { + artifactUploadState.setStatusPopupMinimized(false); + eventBus.publish(this, UploadArtifactUIEvent.MAXIMIZED_STATUS_POPUP); + } + + private void showUploadStatusButton() { + if (uploadStatusButton == null) { + return; + } + uploadStatusButton.setVisible(true); + updateStatusButtonCount(); + } + + protected void hideUploadStatusButton() { + if (uploadStatusButton == null) { + return; + } + uploadStatusButton.setVisible(false); + } + + private void maximizeStatusPopup() { + hideUploadStatusButton(); + uploadInfoWindow.maximizeStatusPopup(); + } + + private void setUploadStatusButtonIconToFinished() { + if (uploadStatusButton == null) { + return; + } + uploadStatusButton.removeStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE); + uploadStatusButton.setIcon(FontAwesome.UPLOAD); + } + + private void setUploadStatusButtonIconToInProgress() { + if (uploadStatusButton == null) { + return; + } + uploadStatusButton.addStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE); + uploadStatusButton.setIcon(null); + } + + protected void updateUploadCounts() { + updateActionCount(); + updateStatusButtonCount(); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadResultWindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadResultWindow.java index c5319a221..f495c59aa 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadResultWindow.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadResultWindow.java @@ -11,14 +11,17 @@ package org.eclipse.hawkbit.ui.artifacts.upload; import java.util.ArrayList; import java.util.List; +import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleTiny; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.I18N; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; +import org.eclipse.hawkbit.ui.utils.SpringContextHelper; +import org.vaadin.spring.events.EventBus; import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; @@ -63,6 +66,9 @@ public class UploadResultWindow implements Button.ClickListener { private static final String UPLOAD_RESULT = "uploadResult"; private static final String REASON = "reason"; + + private transient EventBus.SessionEventBus eventBus; + /** * Initialize upload status popup. @@ -75,12 +81,13 @@ public class UploadResultWindow implements Button.ClickListener { public UploadResultWindow(final List uploadResultList, final I18N i18n) { this.uploadResultList = uploadResultList; this.i18n = i18n; + eventBus = SpringContextHelper.getBean( EventBus.SessionEventBus.class); createComponents(); createLayout(); } private void createComponents() { - closeBtn = SPUIComponentProvider.getButton(SPUIComponetIdProvider.UPLOAD_ARTIFACT_RESULT_CLOSE, + closeBtn = SPUIComponentProvider.getButton(SPUIComponentIdProvider.UPLOAD_ARTIFACT_RESULT_CLOSE, SPUILabelDefinitions.CLOSE, SPUILabelDefinitions.CLOSE, ValoTheme.BUTTON_PRIMARY, false, null, SPUIButtonStyleTiny.class); closeBtn.addClickListener(this); @@ -89,7 +96,7 @@ public class UploadResultWindow implements Button.ClickListener { uploadResultTable.addStyleName("artifact-table"); uploadResultTable.setSizeFull(); uploadResultTable.setImmediate(true); - uploadResultTable.setId(SPUIComponetIdProvider.UPLOAD_RESULT_TABLE); + uploadResultTable.setId(SPUIComponentIdProvider.UPLOAD_RESULT_TABLE); uploadResultTable.addStyleName(ValoTheme.TABLE_BORDERLESS); uploadResultTable.addStyleName(ValoTheme.TABLE_SMALL); uploadResultTable.addStyleName(ValoTheme.TABLE_NO_VERTICAL_LINES); @@ -121,7 +128,7 @@ public class UploadResultWindow implements Button.ClickListener { reasonLabel = HawkbitCommonUtil.getFormatedLabel(uploadResult.getReason()); reasonLabel.setDescription(uploadResult.getReason()); - final String idStr = SPUIComponetIdProvider.UPLOAD_ERROR_REASON + uploadResult.getBaseSwModuleName() + "/" + final String idStr = SPUIComponentIdProvider.UPLOAD_ERROR_REASON + uploadResult.getBaseSwModuleName() + "/" + uploadResult.getFileName(); reasonLabel.setId(idStr); newItem.getItemProperty(REASON).setValue(reasonLabel); @@ -180,9 +187,11 @@ public class UploadResultWindow implements Button.ClickListener { @Override public void buttonClick(final ClickEvent event) { - if (event.getComponent().getId().equals(SPUIComponetIdProvider.UPLOAD_ARTIFACT_RESULT_CLOSE) - || event.getComponent().getId().equals(SPUIComponetIdProvider.UPLOAD_ARTIFACT_RESULT_POPUP_CLOSE)) { + if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_ARTIFACT_RESULT_CLOSE) + || event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_ARTIFACT_RESULT_POPUP_CLOSE)) { uploadResultsWindow.close(); + //close upload status popup if open + eventBus.publish(this, UploadArtifactUIEvent.ARTIFACT_RESULT_POPUP_CLOSED); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusInfoWindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusInfoWindow.java index 8b36ef39e..a58c6ea14 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusInfoWindow.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusInfoWindow.java @@ -8,20 +8,49 @@ */ package org.eclipse.hawkbit.ui.artifacts.upload; -import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent.UploadStatusEventType; +import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; +import org.eclipse.hawkbit.ui.common.ConfirmationDialog; +import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; +import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder; +import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; +import org.eclipse.hawkbit.ui.utils.I18N; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; +import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; +import org.springframework.beans.factory.annotation.Autowired; +import org.vaadin.spring.events.EventBus; +import org.vaadin.spring.events.EventScope; +import org.vaadin.spring.events.annotation.EventBusListenerMethod; + +import com.vaadin.data.Container.Indexed; import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; import com.vaadin.server.FontAwesome; import com.vaadin.shared.ui.window.WindowMode; import com.vaadin.spring.annotation.SpringComponent; import com.vaadin.spring.annotation.ViewScope; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Grid; import com.vaadin.ui.Grid.SelectionMode; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; import com.vaadin.ui.renderers.HtmlRenderer; import com.vaadin.ui.renderers.ProgressBarRenderer; +import com.vaadin.ui.themes.ValoTheme; import elemental.json.JsonValue; @@ -34,7 +63,16 @@ import elemental.json.JsonValue; @ViewScope @SpringComponent -public class UploadStatusInfoWindow extends Window implements Window.CloseListener, Window.WindowModeChangeListener { +public class UploadStatusInfoWindow extends Window { + + @Autowired + private transient EventBus.SessionEventBus eventBus; + + @Autowired + private ArtifactUploadState artifactUploadState; + + @Autowired + private I18N i18n; private static final String PROGRESS = "Progress"; @@ -46,52 +84,173 @@ public class UploadStatusInfoWindow extends Window implements Window.CloseListen private static final long serialVersionUID = 1L; - private final Grid grid; + private Grid grid; - private final IndexedContainer uploads; + private IndexedContainer uploads; private volatile boolean errorOccured = false; + private volatile boolean uploadAborted = false; + + private Button minimizeButton; + + private VerticalLayout mainLayout; + + private Label windowCaption; + + private Button closeButton; + + private Button resizeButton; + + private UI ui; + + private ConfirmationDialog confirmDialog; + /** * Default Constructor. */ - UploadStatusInfoWindow() { - super("Upload Status"); + @PostConstruct + void init() { - addStyleName(SPUIStyleDefinitions.UPLOAD_INFO); - center(); - setImmediate(true); - setResizable(true); - setDraggable(true); - setClosable(true); - uploads = new IndexedContainer(); - uploads.addContainerProperty(STATUS, String.class, "Active"); - uploads.addContainerProperty(FILE_NAME, String.class, null); - uploads.addContainerProperty(PROGRESS, Double.class, 0D); - uploads.addContainerProperty(REASON, String.class, ""); + setPopupProperties(); + createStatusPopupHeaderComponents(); - grid = new Grid(uploads); - grid.addStyleName(SPUIStyleDefinitions.UPLOAD_STATUS_GRID); - grid.setSelectionMode(SelectionMode.NONE); - grid.getColumn(STATUS).setRenderer(new StatusRenderer()); - grid.getColumn(PROGRESS).setRenderer(new ProgressBarRenderer()); - setColumnWidth(); - grid.setFrozenColumnCount(4); - grid.setColumnOrder(STATUS, PROGRESS, FILE_NAME, REASON); - grid.setHeaderVisible(true); - grid.setImmediate(true); + mainLayout = new VerticalLayout(); + mainLayout.setSpacing(Boolean.TRUE); + mainLayout.setSizeUndefined(); setPopupSizeInMinMode(); - setContent(grid); - addCloseListener(this); - addWindowModeChangeListener(this); + uploads = getGridContainer(); + grid = createGrid(); + setGridColumnProperties(); + + mainLayout.addComponents(getCaptionLayout(), grid); + mainLayout.setExpandRatio(grid, 1.0F); + setContent(mainLayout); + eventBus.subscribe(this); + ui = UI.getCurrent(); + + createConfirmDialog(); + } + + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvent(final UploadStatusEvent event) { + if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_IN_PROGRESS) { + UI.getCurrent().access( + () -> updateProgress(event.getUploadStatus().getFileName(), event.getUploadStatus().getBytesRead(), + event.getUploadStatus().getContentLength(), event.getUploadStatus().getSoftwareModule())); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STARTED) { + UI.getCurrent().access(() -> onStartOfUpload(event)); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FAILED) { + ui.access(() -> uploadFailed(event.getUploadStatus().getFileName(), event.getUploadStatus() + .getFailureReason(), event.getUploadStatus().getSoftwareModule())); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_SUCCESSFUL) { + UI.getCurrent().access( + () -> uploadSucceeded(event.getUploadStatus().getFileName(), event.getUploadStatus() + .getSoftwareModule())); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FINISHED) { + ui.access(() -> uploadSucceeded(event.getUploadStatus().getFileName(), event.getUploadStatus() + .getSoftwareModule())); + } + } + + private void onStartOfUpload(UploadStatusEvent event) { + uploadSessionStarted(); + uploadStarted(event.getUploadStatus().getFileName(), event.getUploadStatus().getSoftwareModule()); + } + + @PreDestroy + void destroy() { + /* + * It's good manners to do this, even though vaadin-spring will + * automatically unsubscribe when this UI is garbage collected. + */ + eventBus.unsubscribe(this); + } + + private void restoreState() { + Indexed container = grid.getContainerDataSource(); + if (container.getItemIds().isEmpty()) { + container.removeAllItems(); + for (UploadStatusObject statusObject : artifactUploadState.getUploadedFileStatusList()) { + Item item = container.addItem(getItemid(statusObject.getFilename(), + statusObject.getSelectedSoftwareModule())); + item.getItemProperty(REASON).setValue(statusObject.getReason() != null ? statusObject.getReason() : ""); + item.getItemProperty(STATUS).setValue(statusObject.getStatus()); + item.getItemProperty(PROGRESS).setValue(statusObject.getProgress()); + item.getItemProperty(FILE_NAME).setValue(statusObject.getFilename()); + SoftwareModule sw = statusObject.getSelectedSoftwareModule(); + item.getItemProperty(SPUILabelDefinitions.NAME_VERSION).setValue( + HawkbitCommonUtil.getFormattedNameVersion(sw.getName(), sw.getVersion())); + } + if (artifactUploadState.isUploadCompleted()) { + minimizeButton.setEnabled(false); + } + } + } + + private void setPopupProperties() { + setId(SPUIComponentIdProvider.UPLOAD_STATUS_POPUP_ID); + addStyleName(SPUIStyleDefinitions.UPLOAD_INFO); + setImmediate(true); + setResizable(false); + setDraggable(true); + setClosable(false); + setModal(true); + } + + private void setGridColumnProperties() { + grid.getColumn(STATUS).setRenderer(new StatusRenderer()); + grid.getColumn(PROGRESS).setRenderer(new ProgressBarRenderer()); + grid.setColumnOrder(STATUS, PROGRESS, FILE_NAME, SPUILabelDefinitions.NAME_VERSION, REASON); + setColumnWidth(); + grid.getColumn(SPUILabelDefinitions.NAME_VERSION).setHeaderCaption(i18n.get("upload.swModuleTable.header")); + grid.setFrozenColumnCount(5); + } + + private Grid createGrid() { + Grid statusGrid = new Grid(uploads); + statusGrid.addStyleName(SPUIStyleDefinitions.UPLOAD_STATUS_GRID); + statusGrid.setSelectionMode(SelectionMode.NONE); + statusGrid.setHeaderVisible(true); + statusGrid.setImmediate(true); + statusGrid.setSizeFull(); + return statusGrid; + } + + private IndexedContainer getGridContainer() { + IndexedContainer uploadContainer = new IndexedContainer(); + uploadContainer.addContainerProperty(STATUS, String.class, "Active"); + uploadContainer.addContainerProperty(FILE_NAME, String.class, null); + uploadContainer.addContainerProperty(PROGRESS, Double.class, 0D); + uploadContainer.addContainerProperty(REASON, String.class, ""); + uploadContainer.addContainerProperty(SPUILabelDefinitions.NAME_VERSION, String.class, ""); + return uploadContainer; + } + + private HorizontalLayout getCaptionLayout() { + final HorizontalLayout captionLayout = new HorizontalLayout(); + captionLayout.setSizeFull(); + captionLayout.setHeight("36px"); + captionLayout.addComponents(windowCaption, minimizeButton, resizeButton, closeButton); + captionLayout.setExpandRatio(windowCaption, 1.0F); + captionLayout.addStyleName("v-window-header"); + return captionLayout; + } + + private void createStatusPopupHeaderComponents() { + minimizeButton = getMinimizeButton(); + windowCaption = new Label("Upload status"); + closeButton = getCloseButton(); + resizeButton = getResizeButton(); } private void setColumnWidth() { - grid.getColumn(STATUS).setWidth(70); + grid.getColumn(STATUS).setWidth(60); grid.getColumn(PROGRESS).setWidth(150); - grid.getColumn(FILE_NAME).setWidth(280); - grid.getColumn(REASON).setWidth(300); + grid.getColumn(FILE_NAME).setWidth(200); + grid.getColumn(REASON).setWidth(290); + grid.getColumn(SPUILabelDefinitions.NAME_VERSION).setWidth(200); } private void resetColumnWidth() { @@ -99,15 +258,16 @@ public class UploadStatusInfoWindow extends Window implements Window.CloseListen grid.getColumn(PROGRESS).setWidthUndefined(); grid.getColumn(FILE_NAME).setWidthUndefined(); grid.getColumn(REASON).setWidthUndefined(); - + grid.getColumn(SPUILabelDefinitions.NAME_VERSION).setWidthUndefined(); } private static class StatusRenderer extends HtmlRenderer { + private static final long serialVersionUID = -5365795450234970943L; + @Override public JsonValue encode(final String value) { - - String result = ""; + String result; switch (value) { case "Finished": result = "
" + FontAwesome.CHECK_CIRCLE.getHtml() + "
"; @@ -127,30 +287,66 @@ public class UploadStatusInfoWindow extends Window implements Window.CloseListen * Automatically close if not error has occured. */ void uploadSessionFinished() { - if (!errorOccured) { - close(); + uploadAborted = false; + if (!errorOccured && !artifactUploadState.isStatusPopupMinimized()) { + clearWindow(); } - + artifactUploadState.setUploadCompleted(true); + minimizeButton.setEnabled(false); + closeButton.setEnabled(true); + confirmDialog.getWindow().close(); + UI.getCurrent().removeWindow(confirmDialog.getWindow()); } void uploadSessionStarted() { - close(); + if (artifactUploadState.getNumberOfFilesActuallyUpload().intValue() == 0 + && artifactUploadState.getNumberOfFileUploadsFailed().intValue() == 0 + && !artifactUploadState.isStatusPopupMinimized()) { + openWindow(); + } + if (!uploadAborted) { + minimizeButton.setEnabled(true); + closeButton.setEnabled(true); + artifactUploadState.setUploadCompleted(false); + } + } + + void openWindow() { UI.getCurrent().addWindow(this); center(); } - void uploadStarted(final String filename) { - final Item item = uploads.addItem(filename); - item.getItemProperty(FILE_NAME).setValue(filename); - grid.scrollToEnd(); - + void maximizeStatusPopup() { + openWindow(); + restoreState(); } - void updateProgress(final String filename, final long readBytes, final long contentLength) { - final Item item = uploads.getItem(filename); + void uploadStarted(final String filename, final SoftwareModule softwareModule) { + final Item item = uploads.addItem(getItemid(filename, softwareModule)); if (item != null) { - item.getItemProperty(PROGRESS).setValue((double) readBytes / (double) contentLength); + item.getItemProperty(FILE_NAME).setValue(filename); + item.getItemProperty(SPUILabelDefinitions.NAME_VERSION).setValue( + HawkbitCommonUtil.getFormattedNameVersion(softwareModule.getName(), softwareModule.getVersion())); + } + grid.scrollToEnd(); + UploadStatusObject uploadStatus = new UploadStatusObject(filename, softwareModule); + uploadStatus.setStatus("Active"); + artifactUploadState.getUploadedFileStatusList().add(uploadStatus); + } + void updateProgress(final String filename, final long readBytes, final long contentLength, + final SoftwareModule softwareModule) { + final Item item = uploads.getItem(getItemid(filename, softwareModule)); + double progress = (double) readBytes / (double) contentLength; + if (item != null) { + item.getItemProperty(PROGRESS).setValue(progress); + } + List uploadStatusObjectList = (List) artifactUploadState + .getUploadedFileStatusList().stream().filter(e -> e.getFilename().equals(filename)) + .collect(Collectors.toList()); + if (!uploadStatusObjectList.isEmpty()) { + UploadStatusObject uploadStatusObject = uploadStatusObjectList.get(0); + uploadStatusObject.setProgress(progress); } } @@ -159,67 +355,142 @@ public class UploadStatusInfoWindow extends Window implements Window.CloseListen * * @param filename * of the uploaded file. + * @param softwareModule + * selected software module */ - public void uploadSucceeded(final String filename) { - final Item item = uploads.getItem(filename); + public void uploadSucceeded(final String filename, SoftwareModule softwareModule) { + final Item item = uploads.getItem(getItemid(filename, softwareModule)); + String status = "Finished"; if (item != null) { - item.getItemProperty(STATUS).setValue("Finished"); - + item.getItemProperty(STATUS).setValue(status); + } + List uploadStatusObjectList = (List) artifactUploadState + .getUploadedFileStatusList().stream().filter(e -> e.getFilename().equals(filename)) + .collect(Collectors.toList()); + if (!uploadStatusObjectList.isEmpty()) { + UploadStatusObject uploadStatusObject = uploadStatusObjectList.get(0); + uploadStatusObject.setStatus(status); + uploadStatusObject.setProgress(1d); } } - void uploadFailed(final String filename, final String errorReason) { - final Item item = uploads.getItem(filename); + void uploadFailed(final String filename, final String errorReason, SoftwareModule softwareModule) { + errorOccured = true; + String status = "Failed"; + final Item item = uploads.getItem(getItemid(filename, softwareModule)); if (item != null) { - if (!errorOccured) { - errorOccured = true; - } item.getItemProperty(REASON).setValue(errorReason); - item.getItemProperty(STATUS).setValue("Failed"); - + item.getItemProperty(STATUS).setValue(status); + } + List uploadStatusObjectList = (List) artifactUploadState + .getUploadedFileStatusList().stream().filter(e -> e.getFilename().equals(filename)) + .collect(Collectors.toList()); + if (!uploadStatusObjectList.isEmpty()) { + UploadStatusObject uploadStatusObject = uploadStatusObjectList.get(0); + uploadStatusObject.setStatus(status); + uploadStatusObject.setReason(errorReason); } } - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Window.CloseListener#windowClose(com.vaadin.ui.Window. - * CloseEvent) - */ - @Override - public void windowClose(final CloseEvent e) { - clearWindow(); - } - - private void clearWindow() { + protected void clearWindow() { errorOccured = false; uploads.removeAllItems(); setWindowMode(WindowMode.NORMAL); + setColumnWidth(); + setPopupSizeInMinMode(); + resizeButton.setIcon(FontAwesome.EXPAND); + this.close(); + artifactUploadState.getUploadedFileStatusList().clear(); + artifactUploadState.getNumberOfFileUploadsFailed().set(0); } - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Window.WindowModeChangeListener#windowModeChanged(com. - * vaadin.ui.Window. WindowModeChangeEvent) - */ - @Override - public void windowModeChanged(final WindowModeChangeEvent event) { - if (event.getWindow().getWindowMode() == WindowMode.MAXIMIZED) { + private void setPopupSizeInMinMode() { + mainLayout.setWidth(900, Unit.PIXELS); + mainLayout.setHeight(510, Unit.PIXELS); + } + + private Button getMinimizeButton() { + final Button minimizeBtn = SPUIComponentProvider.getButton( + SPUIComponentIdProvider.UPLOAD_STATUS_POPUP_MINIMIZE_BUTTON_ID, "", "", "", true, FontAwesome.MINUS, + SPUIButtonStyleSmallNoBorder.class); + minimizeBtn.addStyleName(ValoTheme.BUTTON_BORDERLESS); + minimizeBtn.addClickListener(event -> minimizeWindow()); + minimizeBtn.setEnabled(true); + return minimizeBtn; + } + + private Button getResizeButton() { + final Button resizeBtn = SPUIComponentProvider.getButton( + SPUIComponentIdProvider.UPLOAD_STATUS_POPUP_RESIZE_BUTTON_ID, "", "", "", true, FontAwesome.EXPAND, + SPUIButtonStyleSmallNoBorder.class); + resizeBtn.addStyleName(ValoTheme.BUTTON_BORDERLESS); + resizeBtn.addClickListener(event -> resizeWindow(event)); + return resizeBtn; + } + + private void resizeWindow(ClickEvent event) { + if (event.getButton().getIcon() == FontAwesome.EXPAND) { + event.getButton().setIcon(FontAwesome.COMPRESS); + setWindowMode(WindowMode.MAXIMIZED); resetColumnWidth(); grid.getColumn(STATUS).setExpandRatio(0); grid.getColumn(PROGRESS).setExpandRatio(1); grid.getColumn(FILE_NAME).setExpandRatio(2); grid.getColumn(REASON).setExpandRatio(3); - grid.setSizeFull(); + grid.getColumn(SPUILabelDefinitions.NAME_VERSION).setExpandRatio(4); + mainLayout.setSizeFull(); } else { + event.getButton().setIcon(FontAwesome.EXPAND); + setWindowMode(WindowMode.NORMAL); setColumnWidth(); setPopupSizeInMinMode(); } } - private void setPopupSizeInMinMode() { - grid.setWidth(800, Unit.PIXELS); - grid.setHeight(510, Unit.PIXELS); + private void minimizeWindow() { + this.close(); + artifactUploadState.setStatusPopupMinimized(true); + eventBus.publish(this, UploadArtifactUIEvent.MINIMIZED_STATUS_POPUP); + } + + private Button getCloseButton() { + final Button closeBtn = SPUIComponentProvider.getButton( + SPUIComponentIdProvider.UPLOAD_STATUS_POPUP_CLOSE_BUTTON_ID, "", "", "", true, FontAwesome.TIMES, + SPUIButtonStyleSmallNoBorder.class); + closeBtn.addStyleName(ValoTheme.BUTTON_BORDERLESS); + closeBtn.addClickListener(event -> onClose()); + return closeBtn; + } + + private void onClose() { + if (!artifactUploadState.isUploadCompleted()) { + confirmAbortAction(); + } else { + clearWindow(); + } + } + + private void confirmAbortAction() { + UI.getCurrent().addWindow(confirmDialog.getWindow()); + confirmDialog.getWindow().bringToFront(); + } + + private void createConfirmDialog() { + confirmDialog = new ConfirmationDialog(i18n.get("caption.confirm.abort.action"), + i18n.get("message.abort.upload"), i18n.get("button.ok"), i18n.get("button.cancel"), ok -> { + if (ok) { + eventBus.publish(this, UploadStatusEventType.ABORT_UPLOAD); + uploadAborted = true; + errorOccured = true; + minimizeButton.setEnabled(false); + closeButton.setEnabled(false); + } + }); + } + + private String getItemid(final String filename, final SoftwareModule softwareModule) { + return new StringBuilder(filename).append( + HawkbitCommonUtil.getFormattedNameVersion(softwareModule.getName(), softwareModule.getVersion())) + .toString(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusObject.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusObject.java new file mode 100644 index 000000000..eec189eaf --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusObject.java @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.artifacts.upload; + +import java.io.Serializable; + +import org.eclipse.hawkbit.repository.model.SoftwareModule; + +/** + * + * Holds uploaded file status.Used to display the details in upload status + * popup. + * + */ +public class UploadStatusObject implements Serializable { + private static final long serialVersionUID = 1L; + + private String status; + private Double progress; + private String filename; + private String reason; + private final SoftwareModule selectedSoftwareModule; + + public UploadStatusObject(final String status, final Double progress, final String fileName, final String reason, + final SoftwareModule selectedSoftwareModule) { + this(fileName, selectedSoftwareModule); + this.status = status; + this.progress = progress; + this.reason = reason; + } + + public UploadStatusObject(final String fileName, final SoftwareModule selectedSoftwareModule) { + this.filename = fileName; + this.selectedSoftwareModule = selectedSoftwareModule; + } + + public SoftwareModule getSelectedSoftwareModule() { + return selectedSoftwareModule; + } + + public String getStatus() { + return status; + } + + public void setStatus(final String status) { + this.status = status; + } + + public Double getProgress() { + return progress; + } + + public void setProgress(final Double progress) { + this.progress = progress; + } + + public String getFilename() { + return filename; + } + + public void setFilename(final String filename) { + this.filename = filename; + } + + public String getReason() { + return reason; + } + + public void setReason(final String reason) { + this.reason = reason; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((filename == null) ? 0 : filename.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof UploadStatusObject)) { + return false; + } + final UploadStatusObject other = (UploadStatusObject) obj; + if (filename == null) { + if (other.filename != null) { + return false; + } + } else if (!filename.equals(other.filename)) { + return false; + } + return true; + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerConstants.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerConstants.java new file mode 100644 index 000000000..06e280e4e --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerConstants.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.colorpicker; + +import com.vaadin.shared.ui.colorpicker.Color; + +/** + * Provides color constants for the ColorPickerLayout + * + */ +public class ColorPickerConstants { + + public static final String DEFAULT_COLOR = "rgb(44,151,32)"; + public static final Color START_COLOR = new Color(0, 146, 58); + + private ColorPickerConstants() { + + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerHelper.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerHelper.java new file mode 100644 index 000000000..923c58fe3 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerHelper.java @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.colorpicker; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.hawkbit.ui.management.tag.SpColorPickerPreview; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.vaadin.shared.ui.colorpicker.Color; +import com.vaadin.ui.Slider.ValueOutOfBoundsException; + +/** + * Contains helper methods for the ColorPickerLayout to handle the ColorPicker + * + */ +public class ColorPickerHelper { + + private static final Logger LOG = LoggerFactory.getLogger(ColorPickerHelper.class); + + private ColorPickerHelper() { + + } + + /** + * Get color picked value as string. + * + * @return String of color picked value. + */ + public static String getColorPickedString(final SpColorPickerPreview preview) { + + final Color color = preview.getColor(); + return "rgb(" + color.getRed() + "," + color.getGreen() + "," + color.getBlue() + ")"; + } + + /** + * Covert RGB code to {@Color}. + * + * @param value + * RGB vale + * @return Color + */ + public static Color rgbToColorConverter(final String value) { + + if (StringUtils.isEmpty(value) || (StringUtils.isNotEmpty(value) && !value.startsWith("rgb"))) { + throw new IllegalArgumentException( + "String to convert is empty or of invalid format - value: '" + value + "'"); + } + + // RGB color format rgb/rgba(255,255,255,0.1) + final String[] colors = value.substring(value.indexOf('(') + 1, value.length() - 1).split(","); + final int red = Integer.parseInt(colors[0]); + final int green = Integer.parseInt(colors[1]); + final int blue = Integer.parseInt(colors[2]); + if (colors.length > 3) { + final int alpha = (int) (Double.parseDouble(colors[3]) * 255d); + return new Color(red, green, blue, alpha); + } + return new Color(red, green, blue); + } + + /** + * + * Gets the selectedColor in the ColorPickerLayout and sets the slider + * values + * + * @param colorPickerLayout + * colorPickerLayout + */ + public static void setRgbSliderValues(final ColorPickerLayout colorPickerLayout) { + + try { + final double redColorValue = colorPickerLayout.getSelectedColor().getRed(); + colorPickerLayout.getRedSlider().setValue(Double.valueOf(redColorValue)); + final double blueColorValue = colorPickerLayout.getSelectedColor().getBlue(); + colorPickerLayout.getBlueSlider().setValue(Double.valueOf(blueColorValue)); + final double greenColorValue = colorPickerLayout.getSelectedColor().getGreen(); + colorPickerLayout.getGreenSlider().setValue(Double.valueOf(greenColorValue)); + } catch (final ValueOutOfBoundsException e) { + LOG.error("Unable to set RGB color value to " + colorPickerLayout.getSelectedColor().getRed() + "," + + colorPickerLayout.getSelectedColor().getGreen() + "," + + colorPickerLayout.getSelectedColor().getBlue(), e); + } + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerLayout.java new file mode 100644 index 000000000..2c6191bc8 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerLayout.java @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.colorpicker; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.hawkbit.ui.common.CoordinatesToColor; +import org.eclipse.hawkbit.ui.management.tag.SpColorPickerPreview; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; + +import com.vaadin.shared.ui.colorpicker.Color; +import com.vaadin.ui.AbstractColorPicker.Coordinates2Color; +import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Slider; +import com.vaadin.ui.components.colorpicker.ColorPickerGradient; +import com.vaadin.ui.components.colorpicker.ColorSelector; + +/** + * + * Defines the Layout for the ColorPicker + * + */ +public class ColorPickerLayout extends GridLayout { + + private static final long serialVersionUID = -7025970080613796692L; + + private SpColorPickerPreview selPreview; + + private ColorPickerGradient colorSelect; + private Set selectors; + private Color selectedColor; + + /** RGB color converter. */ + private final Coordinates2Color rgbConverter = new CoordinatesToColor(); + + private Slider redSlider; + private Slider greenSlider; + private Slider blueSlider; + + public ColorPickerLayout() { + + setColumns(2); + setRows(4); + setId(SPUIComponentIdProvider.COLOR_PICKER_LAYOUT); + + init(); + + setStyleName("rgb-vertical-layout"); + + addComponent(redSlider, 0, 1); + addComponent(greenSlider, 0, 2); + addComponent(blueSlider, 0, 3); + + addComponent(selPreview, 1, 0); + addComponent(colorSelect, 1, 1, 1, 3); + } + + public void init() { + + selectors = new HashSet<>(); + selectedColor = getDefaultColor(); + selPreview = new SpColorPickerPreview(selectedColor); + + colorSelect = new ColorPickerGradient("rgb-gradient", rgbConverter); + colorSelect.setColor(selectedColor); + colorSelect.setWidth("220px"); + + redSlider = createRGBSlider("", "red"); + redSlider.setId(SPUIComponentIdProvider.COLOR_PICKER_RED_SLIDER); + greenSlider = createRGBSlider("", "green"); + blueSlider = createRGBSlider("", "blue"); + + selectors.add(colorSelect); + } + + public Slider createRGBSlider(final String caption, final String styleName) { + final Slider slider = new Slider(caption, 0, 255); + slider.setImmediate(true); + slider.setWidth("150px"); + slider.addStyleName(styleName); + return slider; + } + + public SpColorPickerPreview getSelPreview() { + return selPreview; + } + + public void setSelPreview(final SpColorPickerPreview selPreview) { + this.selPreview = selPreview; + } + + public ColorPickerGradient getColorSelect() { + return colorSelect; + } + + public void setColorSelect(final ColorPickerGradient colorSelect) { + this.colorSelect = colorSelect; + } + + public Set getSelectors() { + return selectors; + } + + public Color getSelectedColor() { + return selectedColor; + } + + public void setSelectedColor(final Color selectedColor) { + this.selectedColor = selectedColor; + } + + public Coordinates2Color getRgbConverter() { + return rgbConverter; + } + + public Color getDefaultColor() { + return new Color(44, 151, 32); + } + + public Slider getRedSlider() { + return redSlider; + } + + public void setRedSlider(final Slider redSlider) { + this.redSlider = redSlider; + } + + public Slider getGreenSlider() { + return greenSlider; + } + + public void setGreenSlider(final Slider greenSlider) { + this.greenSlider = greenSlider; + } + + public Slider getBlueSlider() { + return blueSlider; + } + + public void setBlueSlider(final Slider blueSlider) { + this.blueSlider = blueSlider; + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CommonDialogWindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CommonDialogWindow.java new file mode 100644 index 000000000..3108455dd --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CommonDialogWindow.java @@ -0,0 +1,493 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.common; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.hawkbit.ui.artifacts.smtable.SoftwareModuleAddUpdateWindow; +import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; +import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorderWithIcon; +import org.eclipse.hawkbit.ui.layouts.AbstractCreateUpdateTagLayout; +import org.eclipse.hawkbit.ui.management.targettable.TargetAddUpdateWindowLayout; +import org.eclipse.hawkbit.ui.utils.I18N; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; +import org.vaadin.hene.flexibleoptiongroup.FlexibleOptionGroupItemComponent; + +import com.google.common.base.Strings; +import com.google.common.collect.Sets; +import com.vaadin.data.Container.ItemSetChangeEvent; +import com.vaadin.data.Container.ItemSetChangeListener; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.data.Validator; +import com.vaadin.data.validator.NullValidator; +import com.vaadin.event.FieldEvents.TextChangeEvent; +import com.vaadin.event.FieldEvents.TextChangeListener; +import com.vaadin.event.FieldEvents.TextChangeNotifier; +import com.vaadin.server.FontAwesome; +import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.AbstractField; +import com.vaadin.ui.AbstractLayout; +import com.vaadin.ui.AbstractOrderedLayout; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Component; +import com.vaadin.ui.Field; +import com.vaadin.ui.GridLayout; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.Link; +import com.vaadin.ui.Table; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.Window; +import com.vaadin.ui.themes.ValoTheme; + +/** + * + * Table pop-up-windows including a minimize and close icon in the upper right + * corner and a save and cancel button at the bottom. Is not intended to reuse. + * + */ +public class CommonDialogWindow extends Window implements Serializable { + + private static final long serialVersionUID = 1L; + + private final VerticalLayout mainLayout = new VerticalLayout(); + + private final String caption; + + private final Component content; + + private final String helpLink; + + private Button saveButton; + + private Button cancelButton; + + private HorizontalLayout buttonsLayout; + + protected ValueChangeListener buttonEnableListener; + + private final ClickListener saveButtonClickListener; + + private final ClickListener cancelButtonClickListener; + + private final ClickListener close = event -> close(); + + private final transient Map orginalValues; + + private final List> allComponents; + + private final I18N i18n; + + /** + * Constructor. + * + * @param caption + * the caption + * @param content + * the content + * @param helpLink + * the helpLinks + * @param saveButtonClickListener + * the saveButtonClickListener + * @param cancelButtonClickListener + * the cancelButtonClickListener + */ + public CommonDialogWindow(final String caption, final Component content, final String helpLink, + final ClickListener saveButtonClickListener, final ClickListener cancelButtonClickListener, + final AbstractLayout layout, final I18N i18n) { + checkNotNull(saveButtonClickListener); + this.caption = caption; + this.content = content; + this.helpLink = helpLink; + this.saveButtonClickListener = saveButtonClickListener; + this.cancelButtonClickListener = cancelButtonClickListener; + this.orginalValues = new HashMap<>(); + this.allComponents = getAllComponents(layout); + this.i18n = i18n; + init(); + } + + @Override + public void close() { + super.close(); + orginalValues.clear(); + removeListeners(); + allComponents.clear(); + this.saveButton.setEnabled(false); + } + + private void removeListeners() { + for (final AbstractField field : allComponents) { + removeTextListener(field); + removeValueChangeListener(field); + removeItemSetChangeistener(field); + } + } + + private void removeItemSetChangeistener(final AbstractField field) { + if (!(field instanceof Table)) { + return; + } + for (final Object listener : field.getListeners(ItemSetChangeEvent.class)) { + if (listener instanceof ChangeListener) { + ((Table) field).removeItemSetChangeListener((ChangeListener) listener); + } + } + } + + private void removeTextListener(final AbstractField field) { + if (!(field instanceof TextChangeNotifier)) { + return; + } + for (final Object listener : field.getListeners(TextChangeEvent.class)) { + if (listener instanceof ChangeListener) { + ((TextChangeNotifier) field).removeTextChangeListener((ChangeListener) listener); + } + } + } + + private void removeValueChangeListener(final AbstractField field) { + for (final Object listener : field.getListeners(ValueChangeEvent.class)) { + if (listener instanceof ChangeListener) { + field.removeValueChangeListener((ChangeListener) listener); + } + } + } + + private final void init() { + + if (content instanceof AbstractOrderedLayout) { + ((AbstractOrderedLayout) content).setSpacing(true); + ((AbstractOrderedLayout) content).setMargin(true); + } + if (content instanceof GridLayout) { + addStyleName("marginTop"); + } + + if (null != content) { + mainLayout.addComponent(content); + } + + createMandatoryLabel(); + + final HorizontalLayout buttonLayout = createActionButtonsLayout(); + mainLayout.addComponent(buttonLayout); + mainLayout.setComponentAlignment(buttonLayout, Alignment.TOP_CENTER); + + setCaption(caption); + setContent(mainLayout); + setResizable(false); + center(); + setModal(true); + addStyleName("fontsize"); + setOrginaleValues(); + addListeners(); + } + + /** + * saves the original values in a Map so we can use them for detecting + * changes + */ + public final void setOrginaleValues() { + for (final AbstractField field : allComponents) { + Object value = field.getValue(); + + if (field instanceof Table) { + value = Sets.newHashSet(((Table) field).getContainerDataSource().getItemIds()); + } + orginalValues.put(field, value); + } + saveButton.setEnabled(isSaveButtonEnabledAfterValueChange(null, null)); + } + + private final void addListeners() { + for (final AbstractField field : allComponents) { + if (field instanceof TextChangeNotifier) { + ((TextChangeNotifier) field).addTextChangeListener(new ChangeListener(field)); + } + + if (field instanceof Table) { + ((Table) field).addItemSetChangeListener(new ChangeListener(field)); + } else { + field.addValueChangeListener(new ChangeListener(field)); + } + } + + saveButton.addClickListener(close); + cancelButton.addClickListener(close); + } + + private boolean isSaveButtonEnabledAfterValueChange(final Component currentChangedComponent, + final Object newValue) { + return isMandatoryFieldNotEmptyAndValid(currentChangedComponent, newValue) + && isValuesChanged(currentChangedComponent, newValue); + } + + private boolean isValuesChanged(final Component currentChangedComponent, final Object newValue) { + for (final AbstractField field : allComponents) { + Object originalValue = orginalValues.get(field); + if (field instanceof CheckBox && originalValue == null) { + originalValue = Boolean.FALSE; + } + final Object currentValue = getCurrentVaue(currentChangedComponent, newValue, field); + + if (!isValueEquals(field, originalValue, currentValue)) { + return true; + } + } + return false; + } + + private boolean isValueEquals(final AbstractField field, final Object orginalValue, final Object currentValue) { + if (Set.class.equals(field.getType())) { + return CollectionUtils.isEqualCollection(CollectionUtils.emptyIfNull((Collection) orginalValue), + CollectionUtils.emptyIfNull((Collection) currentValue)); + } + + if (String.class.equals(field.getType())) { + return Objects.equals(Strings.emptyToNull((String) orginalValue), + Strings.emptyToNull((String) currentValue)); + } + + return Objects.equals(orginalValue, currentValue); + } + + private Object getCurrentVaue(final Component currentChangedComponent, final Object newValue, + final AbstractField field) { + Object currentValue = field.getValue(); + if (field instanceof Table) { + currentValue = ((Table) field).getContainerDataSource().getItemIds(); + } + + if (field.equals(currentChangedComponent)) { + currentValue = newValue; + } + return currentValue; + } + + private boolean shouldMandatoryLabelShown() { + for (final AbstractField field : allComponents) { + if (field.isRequired()) { + return true; + } + } + + return false; + } + + private boolean isMandatoryFieldNotEmptyAndValid(final Component currentChangedComponent, final Object newValue) { + + boolean valid = true; + final List> requiredComponents = allComponents.stream().filter(field -> field.isRequired()) + .collect(Collectors.toList()); + + requiredComponents.addAll(allComponents.stream().filter(this::hasNullValidator).collect(Collectors.toList())); + + for (final AbstractField field : requiredComponents) { + Object value = getCurrentVaue(currentChangedComponent, newValue, field); + + if (String.class.equals(field.getType())) { + value = Strings.emptyToNull((String) value); + } + + if (Set.class.equals(field.getType())) { + value = emptyToNull((Collection) value); + } + + if (value == null) { + return false; + } + + // We need to loop through the entire loop for validity testing. + // Otherwise the UI will only mark the + // first field with errors and then stop. If there are several + // fields with errors, this is bad. + field.setValue(value); + if (!field.isValid()) { + valid = false; + } + } + + return valid; + } + + private static Object emptyToNull(final Collection c) { + return (c == null || c.isEmpty()) ? null : c; + } + + private boolean hasNullValidator(final Component component) { + + if (component instanceof AbstractField) { + final AbstractField fieldComponent = (AbstractField) component; + for (final Validator validator : fieldComponent.getValidators()) { + if (validator instanceof NullValidator) { + return true; + } + } + } + return false; + } + + private List> getAllComponents(final AbstractLayout abstractLayout) { + final List> components = new ArrayList<>(); + + final Iterator iterate = abstractLayout.iterator(); + while (iterate.hasNext()) { + final Component c = iterate.next(); + if (c instanceof AbstractLayout) { + components.addAll(getAllComponents((AbstractLayout) c)); + } + + if (c instanceof AbstractField) { + components.add((AbstractField) c); + } + + if (c instanceof FlexibleOptionGroupItemComponent) { + components.add(((FlexibleOptionGroupItemComponent) c).getOwner()); + } + } + return components; + } + + private HorizontalLayout createActionButtonsLayout() { + + buttonsLayout = new HorizontalLayout(); + buttonsLayout.setSizeFull(); + buttonsLayout.setSpacing(true); + buttonsLayout.addStyleName("actionButtonsMargin"); + + createSaveButton(); + createCancelButton(); + + addHelpLink(); + + return buttonsLayout; + } + + private void createMandatoryLabel() { + + if (!shouldMandatoryLabelShown()) { + return; + } + + final Label mandatoryLabel = new Label(i18n.get("label.mandatory.field")); + mandatoryLabel.addStyleName(SPUIStyleDefinitions.SP_TEXTFIELD_ERROR + " " + ValoTheme.LABEL_TINY); + + if (content instanceof TargetAddUpdateWindowLayout) { + ((TargetAddUpdateWindowLayout) content).getFormLayout().addComponent(mandatoryLabel); + } else if (content instanceof SoftwareModuleAddUpdateWindow) { + ((SoftwareModuleAddUpdateWindow) content).getFormLayout().addComponent(mandatoryLabel); + } else if (content instanceof AbstractCreateUpdateTagLayout) { + ((AbstractCreateUpdateTagLayout) content).getMainLayout().addComponent(mandatoryLabel); + } + + mainLayout.addComponent(mandatoryLabel); + } + + private void createCancelButton() { + cancelButton = SPUIComponentProvider.getButton(SPUIComponentIdProvider.CANCEL_BUTTON, "Cancel", "", "", true, + FontAwesome.TIMES, SPUIButtonStyleNoBorderWithIcon.class); + cancelButton.setSizeUndefined(); + if (cancelButtonClickListener != null) { + cancelButton.addClickListener(cancelButtonClickListener); + } + + buttonsLayout.addComponent(cancelButton); + buttonsLayout.setComponentAlignment(cancelButton, Alignment.MIDDLE_LEFT); + buttonsLayout.setExpandRatio(cancelButton, 1.0F); + } + + private void createSaveButton() { + saveButton = SPUIComponentProvider.getButton(SPUIComponentIdProvider.SAVE_BUTTON, "Save", "", "", true, + FontAwesome.SAVE, SPUIButtonStyleNoBorderWithIcon.class); + saveButton.setSizeUndefined(); + saveButton.addClickListener(saveButtonClickListener); + saveButton.setEnabled(false); + buttonsLayout.addComponent(saveButton); + buttonsLayout.setComponentAlignment(saveButton, Alignment.MIDDLE_RIGHT); + buttonsLayout.setExpandRatio(saveButton, 1.0F); + } + + private void addHelpLink() { + + if (StringUtils.isEmpty(helpLink)) { + return; + } + final Link helpLinkComponent = SPUIComponentProvider.getHelpLink(helpLink); + buttonsLayout.addComponent(helpLinkComponent); + buttonsLayout.setComponentAlignment(helpLinkComponent, Alignment.MIDDLE_RIGHT); + } + + public AbstractComponent getButtonsLayout() { + return this.buttonsLayout; + } + + private class ChangeListener implements ValueChangeListener, TextChangeListener, ItemSetChangeListener { + + private final Field field; + + public ChangeListener(final Field field) { + super(); + this.field = field; + } + + @Override + public void textChange(final TextChangeEvent event) { + saveButton.setEnabled(isSaveButtonEnabledAfterValueChange(field, event.getText())); + } + + @Override + public void valueChange(final ValueChangeEvent event) { + saveButton.setEnabled(isSaveButtonEnabledAfterValueChange(field, field.getValue())); + } + + @Override + public void containerItemSetChange(final ItemSetChangeEvent event) { + if (!(field instanceof Table)) { + return; + } + final Table table = (Table) field; + saveButton.setEnabled( + isSaveButtonEnabledAfterValueChange(table, table.getContainerDataSource().getItemIds())); + } + } + + /** + * Adds the component manually to the allComponents-List and adds a + * ValueChangeListener to it. Necessary in Update Distribution Type as the + * CheckBox concerned is an ItemProperty... + * + * @param component + * AbstractField + */ + public void updateAllComponents(final AbstractField component) { + + allComponents.add(component); + component.addValueChangeListener(new ChangeListener(component)); + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ConfirmationDialog.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ConfirmationDialog.java index c0f42909d..bd1f4cb9e 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ConfirmationDialog.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ConfirmationDialog.java @@ -10,7 +10,7 @@ package org.eclipse.hawkbit.ui.common; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleTiny; -import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; import com.vaadin.server.Resource; @@ -82,13 +82,14 @@ public class ConfirmationDialog implements Button.ClickListener { window.setIcon(icon); } - okButton = SPUIComponentProvider.getButton(SPUIComponetIdProvider.OK_BUTTON, okLabel, "", + okButton = SPUIComponentProvider.getButton(SPUIComponentIdProvider.OK_BUTTON, okLabel, "", ValoTheme.BUTTON_PRIMARY, false, null, SPUIButtonStyleTiny.class); okButton.addClickListener(this); final Button cancelButton = SPUIComponentProvider.getButton(null, cancelLabel, "", null, false, null, SPUIButtonStyleTiny.class); cancelButton.addClickListener(this); + cancelButton.setId(SPUIComponentIdProvider.CANCEL_BUTTON); window.setModal(true); window.addStyleName(SPUIStyleDefinitions.CONFIRMBOX_WINDOW_SYLE); if (this.callback == null) { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetIdName.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/DistributionSetIdName.java similarity index 80% rename from hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetIdName.java rename to hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/DistributionSetIdName.java index f8662567a..66101fbd4 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetIdName.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/DistributionSetIdName.java @@ -6,10 +6,12 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.model; +package org.eclipse.hawkbit.ui.common; import java.io.Serializable; +import org.eclipse.hawkbit.repository.model.DistributionSet; + /** * * @@ -20,6 +22,17 @@ public class DistributionSetIdName implements Serializable { private final Long id; private final String name; private final String version; + + public static DistributionSetIdName generate(final DistributionSet distributionSet) { + return new DistributionSetIdName(distributionSet.getId(), distributionSet.getName(), + distributionSet.getVersion()); + + } + + public static DistributionSetIdName generate(final Long id, final String name, final String version) { + return new DistributionSetIdName(id, name, version); + + } /** * @param id diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/DistributionSetTypeBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/DistributionSetTypeBeanQuery.java index b09255bc7..ded26b254 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/DistributionSetTypeBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/DistributionSetTypeBeanQuery.java @@ -13,6 +13,7 @@ import java.util.List; import java.util.Map; import org.eclipse.hawkbit.repository.DistributionSetManagement; +import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; @@ -41,6 +42,7 @@ public class DistributionSetTypeBeanQuery extends AbstractBeanQuery firstPageDistSetType = null; private transient DistributionSetManagement distributionSetManagement; + private transient EntityFactory entityFactory; /** * Parametric constructor. @@ -57,8 +59,9 @@ public class DistributionSetTypeBeanQuery extends AbstractBeanQuery loadBeans(final int startIndex, final int count) { Page typeBeans; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/SoftwareModuleTypeBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/SoftwareModuleTypeBeanQuery.java index 6fd382084..8705f7aa9 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/SoftwareModuleTypeBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/SoftwareModuleTypeBeanQuery.java @@ -11,6 +11,7 @@ package org.eclipse.hawkbit.ui.common; import java.util.List; import java.util.Map; +import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; @@ -31,6 +32,7 @@ public class SoftwareModuleTypeBeanQuery extends AbstractBeanQuery firstPageSwModuleType = null; private transient SoftwareManagement softwareManagement; + private transient EntityFactory entityFactory; /** * Parametric constructor. @@ -47,7 +49,14 @@ public class SoftwareModuleTypeBeanQuery extends AbstractBeanQuery extends * it as we need full description. */ descLabel.removeStyleName("label-style"); - descLabel.setId(SPUIComponetIdProvider.DETAILS_DESCRIPTION_LABEL_ID); + descLabel.setId(SPUIComponentIdProvider.DETAILS_DESCRIPTION_LABEL_ID); descriptionLayout.addComponent(descLabel); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetailsTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetailsTable.java index c0ecf9869..6e4c7dddd 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetailsTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetailsTable.java @@ -16,6 +16,7 @@ import org.eclipse.hawkbit.repository.exception.EntityLockedException; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.ui.common.DistributionSetIdName; import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder; @@ -214,7 +215,7 @@ public class SoftwareModuleDetailsTable extends Table { .getItem(event.getButton().getId()).getItemProperty(SOFT_MODULE).getValue(), alreadyAssignedSwModules); final DistributionSet newDistributionSet = distributionSetManagement.unassignSoftwareModule(distributionSet, unAssignedSw); - manageDistUIState.setLastSelectedEntity(newDistributionSet.getDistributionSetIdName()); + manageDistUIState.setLastSelectedEntity(DistributionSetIdName.generate(newDistributionSet)); eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.SELECTED_ENTITY, newDistributionSet)); eventBus.publish(this, DistributionsUIEvent.ORDER_BY_DISTRIBUTION); uiNotification.displaySuccess(i18n.get("message.sw.unassigned", unAssignedSw.getName())); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterButtons.java index b64578782..aec0029d0 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterButtons.java @@ -34,19 +34,15 @@ import com.vaadin.ui.themes.ValoTheme; /** * Parent class for filter button layout. - * - * - * - * */ public abstract class AbstractFilterButtons extends Table { private static final long serialVersionUID = 7783305719009746375L; - + private static final String DEFAULT_GREEN = "rgb(44,151,32)"; protected static final String FILTER_BUTTON_COLUMN = "filterButton"; - + @Autowired protected transient EventBus.SessionEventBus eventBus; @@ -63,7 +59,7 @@ public abstract class AbstractFilterButtons extends Table { createTable(); eventBus.subscribe(this); } - + @PreDestroy void destroy() { eventBus.unsubscribe(this); @@ -125,8 +121,7 @@ public abstract class AbstractFilterButtons extends Table { } else if (id != null && isClickedByDefault(name)) { filterButtonClickBehaviour.setDefaultClickedButton(typeButton); } - final DragAndDropWrapper wrapper = createDragAndDropWrapper(typeButton, name, id); - return wrapper; + return createDragAndDropWrapper(typeButton, name, id); } protected boolean isNoTagSateSelected() { @@ -156,6 +151,7 @@ public abstract class AbstractFilterButtons extends Table { columnIds.add(FILTER_BUTTON_COLUMN); setVisibleColumns(columnIds.toArray()); setColumnHeaderMode(ColumnHeaderMode.HIDDEN); + setColumnWidth(FILTER_BUTTON_COLUMN, 137); } private Button createFilterButton(final Long id, final String name, final String description, final String color, @@ -180,6 +176,7 @@ public abstract class AbstractFilterButtons extends Table { button.setDescription(name); } button.setData(id == null ? SPUIDefinitions.NO_TAG_BUTTON_ID : itemId); + return button; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterHeader.java index ddc2d9889..ae497e41e 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterHeader.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterHeader.java @@ -34,7 +34,6 @@ public abstract class AbstractFilterHeader extends VerticalLayout { private static final long serialVersionUID = -1388340600522323332L; - @Autowired protected SpPermissionChecker permChecker; @@ -64,7 +63,7 @@ public abstract class AbstractFilterHeader extends VerticalLayout { if (hasCreateUpdatePermission() && isAddTagRequired()) { config = SPUIComponentProvider.getButton(getConfigureFilterButtonId(), "", "", "", true, FontAwesome.COG, SPUIButtonStyleSmallNoBorder.class); - config.addClickListener(event -> settingsIconClicked(event)); + config.addClickListener(this::settingsIconClicked); } hideIcon = SPUIComponentProvider.getButton(getHideButtonId(), "", "", "", true, FontAwesome.TIMES, SPUIButtonStyleSmallNoBorder.class); @@ -92,8 +91,7 @@ public abstract class AbstractFilterHeader extends VerticalLayout { } private Label createHeaderCaption() { - final Label captionLabel = SPUIComponentProvider.getLabel(getTitle(), SPUILabelDefinitions.SP_WIDGET_CAPTION); - return captionLabel; + return SPUIComponentProvider.getLabel(getTitle(), SPUILabelDefinitions.SP_WIDGET_CAPTION); } /** diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterMultiButtonClick.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterMultiButtonClick.java index 8b3ac4cde..f7d3656b1 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterMultiButtonClick.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterMultiButtonClick.java @@ -22,7 +22,8 @@ import com.vaadin.ui.Button.ClickEvent; */ public abstract class AbstractFilterMultiButtonClick extends AbstractFilterButtonClickBehaviour { - protected final Set