diff --git a/README.md b/README.md index e824971e9..639988af8 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,31 @@ Build: [![Circle CI](https://circleci.com/gh/eclipse/hawkbit.svg?style=svg)](htt * You can also check out our [Project Homepage](https://projects.eclipse.org/projects/iot.hawkbit) for further contact options. -# Compile -``` -mvn install -``` - -# Run and use +# Compile, Run and Getting Started We are not providing an off the shelf installation ready hawkBit update server. However, we recommend to check out the [Example Application](examples/hawkbit-example-app) for a runtime ready Spring Boot based update server that is empowered by hawkBit. +#### Clone and build hawkBit +``` +$ git clone https://github.com/eclipse/hawkbit.git +$ mvn clean install +``` +#### Start hawkBit example app +[Example Application](examples/hawkbit-example-app) +``` +$ java –jar ./examples/hawkbit-example-app/target/hawkbit-example-app-#version#.jar +``` +#### Start hawkBit device simulator +[Device Simulator](examples/hawkbit-device-simulator) +``` +$ 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) +``` +$ java –jar ./examples/hawkbit-mgmt-api-client/target/hawkbit-mgmt-api-client-#version#.jar +``` + # Releases and Roadmap * We are currently working on the first formal release under the Eclipse banner: 0.1 (see [Release 0.1 branch](https://github.com/eclipse/hawkbit/tree/release-train-0.1)). @@ -29,11 +45,10 @@ We are not providing an off the shelf installation ready hawkBit update server. * And of course tons of usability improvements and bug fixes. -## Try out examples -#### Standalone Test Application Server -[Example Application](examples/hawkbit-example-app) -#### Device Simulator using the DMF AMQP API -[Device Simulator](examples/hawkbit-device-simulator) +# Device Integration +There are two device integration APIs provided by the hawkbit update server. +* [Direct Device Integration API (HTTP)](DDIA.md) +* [Device Management Federation API (AMQP)](DMFA.md) # Modules `hawkbit-core` : core elements. @@ -49,9 +64,3 @@ We are not providing an off the shelf installation ready hawkBit update server. `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. - - -# Device Integration -There are two device integration APIs provided by the hawkbit update server. -* [Direct Device Integration API (HTTP)](DDIA.md) -* [Device Management Federation API (AMQP)](DMFA.md) 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 1417c3153..b58d3a413 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 @@ -10,7 +10,6 @@ package org.eclipse.hawkbit.simulator; import java.util.concurrent.ScheduledExecutorService; -import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater.UpdaterCallback; import org.eclipse.hawkbit.simulator.http.ControllerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,28 +81,27 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice { final String deploymentJson = controllerResource.getDeployment(getTenant(), getId(), actionId); final String swVersion = JsonPath.parse(deploymentJson).read("deployment.chunks[0].version"); currentActionId = actionId; - deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, new UpdaterCallback() { - @Override - public void updateFinished(final AbstractSimulatedDevice device, final Long actionId) { - switch (device.getResponseStatus()) { - case SUCCESSFUL: - controllerResource.postSuccessFeedback(getTenant(), getId(), actionId); - break; - case ERROR: - controllerResource.postErrorFeedback(getTenant(), getId(), actionId); - break; - default: - throw new IllegalStateException("simulated device has an unknown response status + " - + device.getResponseStatus()); - } - currentActionId = null; + deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, (device, actionId1) -> { + switch (device.getResponseStatus()) { + case SUCCESSFUL: + controllerResource.postSuccessFeedback(getTenant(), getId(), + actionId1); + break; + case ERROR: + controllerResource.postErrorFeedback(getTenant(), getId(), + actionId1); + break; + default: + throw new IllegalStateException( + "simulated device has an unknown response status + " + device.getResponseStatus()); } + currentActionId = null; }); } } catch (final PathNotFoundException e) { // href might not be in the json response, so ignore // exception here. - LOGGER.trace("Response does not contain a deploymentbase href link, ignoring."); + LOGGER.trace("Response does not contain a deploymentbase href link, ignoring.", e); } } 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 6e93b7d04..075f30ba0 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.simulator; +import java.security.SecureRandom; import java.util.Random; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -41,7 +42,7 @@ public class DeviceSimulatorUpdater { /** * Starting an simulated update process of an simulated device. - * + * * @param tenant * the tenant of the device * @param id @@ -66,7 +67,7 @@ public class DeviceSimulatorUpdater { } private static final class DeviceSimulatorUpdateThread implements Runnable { - private static final Random rndSleep = new Random(); + private static final Random rndSleep = new SecureRandom(); private final AbstractSimulatedDevice device; private final SpSenderService spSenderService; @@ -74,9 +75,8 @@ public class DeviceSimulatorUpdater { private final EventBus eventbus; private final UpdaterCallback callback; - private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device, - final SpSenderService spSenderService, final long actionId, final EventBus eventbus, - final UpdaterCallback callback) { + private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device, final SpSenderService spSenderService, + final long actionId, final EventBus eventbus, final UpdaterCallback callback) { this.device = device; this.spSenderService = spSenderService; this.actionId = actionId; @@ -89,8 +89,9 @@ public class DeviceSimulatorUpdater { final double newProgress = device.getProgress() + 0.2; device.setProgress(newProgress); if (newProgress < 1.0) { - threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, - callback), rndSleep.nextInt(3000), TimeUnit.MILLISECONDS); + threadPool.schedule( + new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback), + rndSleep.nextInt(3000), TimeUnit.MILLISECONDS); } else { callback.updateFinished(device, actionId); } @@ -102,7 +103,7 @@ public class DeviceSimulatorUpdater { * Callback interface which is called when the simulated update process has * been finished and the caller of starting the simulated update process can * send the result to the hawkbit update server back. - * + * * @author Michael Hirsch * */ @@ -111,7 +112,7 @@ public class DeviceSimulatorUpdater { /** * Callback method to indicate that the simulated update process has * been finished. - * + * * @param device * the device which has been updated * @param actionId 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 81acf897e..9c78ec65a 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 @@ -16,6 +16,8 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -24,13 +26,15 @@ import com.google.common.eventbus.EventBus; /** * Poll time trigger which executes the {@link DDISimulatedDevice#poll()} every * second. - * + * * @author Michael Hirsch * */ @Component public class NextPollTimeController { + private static final Logger LOGGER = LoggerFactory.getLogger(NextPollTimeController.class); + private static final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); private static final ExecutorService pollService = Executors.newFixedThreadPool(1); @@ -58,14 +62,9 @@ public class NextPollTimeController { if (nextCounter < 0) { if (device instanceof DDISimulatedDevice) { try { - pollService.submit(new Runnable() { - @Override - public void run() { - ((DDISimulatedDevice) device).poll(); - } - }); - } catch (final Exception e) { - + pollService.submit(() -> ((DDISimulatedDevice) device).poll()); + } catch (final IllegalStateException e) { + LOGGER.trace("Device could not be polled", e); } nextCounter = ((DDISimulatedDevice) device).getPollDelaySec(); } diff --git a/examples/hawkbit-mgmt-api-client/README.md b/examples/hawkbit-mgmt-api-client/README.md index 7eb32f9e6..eff301e20 100644 --- a/examples/hawkbit-mgmt-api-client/README.md +++ b/examples/hawkbit-mgmt-api-client/README.md @@ -1,3 +1,39 @@ +# HawkBit management API example + Example client that shows how to efficiently use the hawkBit management API. -Powered by [Feign](https://github.com/Netflix/feign). \ No newline at end of file +Powered by [Feign](https://github.com/Netflix/feign). + +## How to run the example client + +Run getting started example + + + + $ java -jar hawkbit-mgmt-api-client-#version#.jar + + +Run create and start rollout example + + + $ java -jar hawkbit-mgmt-api-client-#version#.jar --createrollout + + +## This example shows + +In getting started example: +* creating software modules type +* creating distribution set type +* creating distribution sets +* creating software modules +* assigning software modules to distribution sets + +In rollout mode: +* creating software modules type +* creating distribution set type +* creating distribution sets +* creating software modules +* assigning software modules to distribution sets +* creating a rollout +* starting a rollout + diff --git a/examples/hawkbit-mgmt-api-client/pom.xml b/examples/hawkbit-mgmt-api-client/pom.xml index cced3dfbb..6e62bfe4e 100644 --- a/examples/hawkbit-mgmt-api-client/pom.xml +++ b/examples/hawkbit-mgmt-api-client/pom.xml @@ -16,9 +16,43 @@ hawkbit-examples-parent 0.2.0-SNAPSHOT + jar hawkbit-mgmt-api-client hawkBit Management API example client + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + ${baseDir} + false + org.eclipse.hawkbit.mgmt.client.Application + JAR + + + + + + + + + + + org.springframework.cloud + spring-cloud-netflix + 1.0.7.RELEASE + pom + import + + + @@ -26,45 +60,32 @@ hawkbit-rest-api ${project.version} - - com.netflix.feign - feign-jackson - 8.12.1 - com.netflix.feign feign-core - 8.12.1 + + 8.14.2 - - - org.eclipse.hawkbit - hawkbit-example-app - ${project.version} - test + hibernate-validator + org.hibernate org.springframework.boot - spring-boot-starter-test - test + spring-boot-starter - ru.yandex.qatools.allure - allure-junit-adaptor - test + org.springframework.cloud + spring-cloud-starter-feign - org.easytesting - fest-assert-core - test + org.springframework.boot + spring-boot-starter-logging - org.easytesting - fest-assert - test + com.google.collections + google-collections + 1.0-rc2 - - \ No newline at end of file diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/DistributionSetResource.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/DistributionSetResource.java deleted file mode 100644 index 62c987ae8..000000000 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/DistributionSetResource.java +++ /dev/null @@ -1,38 +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.api.client; - -import java.util.List; - -import org.eclipse.hawkbit.rest.resource.RestConstants; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPost; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest; - -import feign.Headers; -import feign.RequestLine; - -/** - * Client binding for the Distribution resource of the management API. - */ -@FunctionalInterface -public interface DistributionSetResource { - - /** - * Creates a list of distribution sets. - * - * @param sets - * the request body java bean containing the necessary attributes - * for creating a distribution set. - * @return the list of targets which have been created - */ - @RequestLine("POST " + RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING) - @Headers("Content-Type: application/json") - DistributionSetsRest createDistributionSets(final List sets); - -} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/DistrubutionSetTagResource.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/DistrubutionSetTagResource.java deleted file mode 100644 index fe7a147a8..000000000 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/DistrubutionSetTagResource.java +++ /dev/null @@ -1,138 +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.api.client; - -import java.util.List; - -import org.eclipse.hawkbit.rest.resource.RestConstants; -import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest; -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.rest.resource.model.tag.TagsRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest; - -import feign.Headers; -import feign.Param; -import feign.RequestLine; - -/** - * Client binding for the DistributionSetTag resource of the management API. - */ -public interface DistrubutionSetTagResource { - - /** - * Retrieves a single distributionset tag based on the given ID. - * - * @param dsTagId - * the ID of the distributionset tag to retrieve - * @return a deserialized java bean containing the attributes of the - * returned distributionset tag - */ - @RequestLine("GET " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/{dsTagId}") - TagRest getDistributionSetTag(@Param("dsTagId") Long dsTagId); - - /** - * Creates a list of distributionset tags. - * - * @param tags - * the tags to be created - * @return the created tag list - */ - @RequestLine("POST " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING) - @Headers("Content-Type: application/json") - TagsRest createDistributionSetTags(List tags); - - /** - * Update attributes of a distributionset tag. - * - * @param dsTagId - * the distributionset tag id to be updated - * @param tag - * the request body - * @return the updated distributionset tag - */ - @RequestLine("PUT " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/{dsTagId}") - @Headers("Content-Type: application/json") - TagRest updateDistributionSetTag(@Param("dsTagId") Long dsTagId, TagRequestBodyPut tag); - - /** - * Deletes given distributionset tag on given ID. - * - * @param dsTagId - * to be deleted - */ - @RequestLine("DELETE " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/{dsTagId}") - void deleteDistributionSetTag(@Param("dsTagId") final Long dsTagId); - - /** - * Retrieves a all assigned targets on the given distributionset tag id. - * - * @param dsTagId - * the ID of the distributionset tag to retrieve - * @return a list of targets - */ - @RequestLine("GET " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING - + RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING) - DistributionSetsRest getAssignedDistributionSets(@Param("dsTagId") final Long dsTagId); - - /** - * Toggle the tag assignment all assigned targets will be unassigned and all - * unassigned targets will be assigned. - * - * @param dsTagId - * the ID of the distributionset tag to toggle - * @param assignedTargetRequestBodies - * a list of controller ids - * @return a list of assigned and unassigned targets - */ - @RequestLine("POST " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING - + RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING + "/toggleTagAssignment") - @Headers("Content-Type: application/json") - DistributionSetTagAssigmentResultRest toggleTagAssignment(@Param("dsTagId") final Long dsTagId, - final List assignedTargetRequestBodies); - - /** - * Assign targets to a given distributionset tag id. - * - * @param dsTagId - * the ID of the distributionset tag to add the targets - * @param assignedTargetRequestBodies - * a list of controller ids - * @return a list of assigned targets - */ - @RequestLine("POST " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING - + RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING) - @Headers("Content-Type: application/json") - TargetsRest assignDistributionSets(@Param("dsTagId") final Long dsTagId, - final List assignedTargetRequestBodies); - - /** - * Unassign targets to a given distributionset tag id. - * - * @param dsTagId - * the ID of the distributionset tag to add the targets - */ - @RequestLine("DELETE " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING - + RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING) - void unassignDistributionSets(@Param("dsTagId") final Long dsTagId); - - /** - * Unassign one target to a given distributionset tag id. - * - * @param dsTagId - * the ID of the distributionset tag to add the targets param - * @param dsId - * the distributionset id - */ - @RequestLine("DELETE " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING - + RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING + "/{dsId}") - void unassignDistributionSet(@Param("dsTagId") final Long dsTagId, @Param("dsId") final Long dsId); -} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/TargetResource.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/TargetResource.java deleted file mode 100644 index 66c147426..000000000 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/TargetResource.java +++ /dev/null @@ -1,80 +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.api.client; - -import java.util.List; - -import org.eclipse.hawkbit.rest.resource.model.target.TargetPagedList; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest; - -import feign.Headers; -import feign.Param; -import feign.RequestLine; - -/** - * Client binding for the Target resource of the management API. - */ -public interface TargetResource { - - /** - * Retrieves a single target based on the given ID. - * - * @param targetId - * the ID of the target to retrieve - * @return a deserialized java bean containing the attributes of the - * returned target - */ - @RequestLine("GET /rest/v1/targets/{targetId}") - TargetRest getTarget(@Param("targetId") final String targetId); - - /** - * Paged query of targets resource. - * - * @param pagingOffsetParam - * of the paged query - * @param pagingLimitParam - * of the paged query - * @return paged list of target entries - */ - @RequestLine("GET /rest/v1/targets?offset={pagingOffsetParam}&limit={pagingLimitParam}") - TargetPagedList getTargets(@Param("pagingOffsetParam") int pagingOffsetParam, - @Param("pagingLimitParam") int pagingLimitParam); - - /** - * Paged query of targets resource with default offset and limit. - * - * @return paged list of target entries - */ - @RequestLine("GET /rest/v1/targets") - TargetPagedList getTargets(); - - /** - * Deletes given target based on given ID. - * - * @param targetId - * to be deleted - */ - @RequestLine("DELETE /rest/v1/targets/{targetId}") - void deleteTarget(@Param("targetId") final String targetId); - - /** - * Creates a list of targets. - * - * @param targets - * the request body java bean containing the necessary attributes - * for creating a target. - * @return the list of targets which have been created - */ - @RequestLine("POST /rest/v1/targets/") - @Headers("Content-Type: application/json") - TargetsRest createTargets(List targets); - -} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/TargetTagResource.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/TargetTagResource.java deleted file mode 100644 index bd74e52d7..000000000 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/TargetTagResource.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.api.client; - -import java.util.List; - -import org.eclipse.hawkbit.rest.resource.RestConstants; -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.TagsRest; -import org.eclipse.hawkbit.rest.resource.model.tag.TargetTagAssigmentResultRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest; - -import feign.Headers; -import feign.Param; -import feign.RequestLine; - -/** - * Client binding for the Target resource of the management API. - */ -public interface TargetTagResource { - - /** - * Retrieves a single target tag based on the given ID. - * - * @param targetTagId - * the ID of the target tag to retrieve - * @return a deserialized java bean containing the attributes of the - * returned target tag - */ - @RequestLine("GET " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/{targetTagId}") - TagRest getTargetTag(@Param("targetTagId") Long targetTagId); - - /** - * Creates a list of target tags. - * - * @param tags - * the tags to be created - * @return the created tag list - */ - @RequestLine("POST " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING) - @Headers("Content-Type: application/json") - TagsRest createTargetTag(List tags); - - /** - * Update attributes of a target tag. - * - * @param targetTagId - * the target tag id to be updated - * @param tag - * the request body - * @return the updated target tag - */ - @RequestLine("PUT " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/{targetTagId}") - @Headers("Content-Type: application/json") - TagRest updateTagretTag(@Param("targetTagId") Long targetTagId, TagRequestBodyPut tag); - - /** - * Deletes given target tag on given ID. - * - * @param targetTagId - * to be deleted - */ - @RequestLine("DELETE " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/{targetTagId}") - void deleteTargetTag(@Param("targetTagId") final Long targetTagId); - - /** - * Retrieves a all assigned targets on the given target tag id. - * - * @param targetTagId - * the ID of the target tag to retrieve - * @return a list of targets - */ - @RequestLine("GET " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING - + RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING) - TargetsRest getAssignedTargets(@Param("targetTagId") final Long targetTagId); - - /** - * Toggle the tag assignment all assigned targets will be unassigned and all - * unassigned targets will be assigned. - * - * @param targetTagId - * the ID of the target tag to toggle - * @param assignedTargetRequestBodies - * a list of controller ids - * @return a list of assigned and unassigned targets - */ - @RequestLine("POST " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING - + RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING + "/toggleTagAssignment") - @Headers("Content-Type: application/json") - TargetTagAssigmentResultRest toggleTagAssignment(@Param("targetTagId") final Long targetTagId, - final List assignedTargetRequestBodies); - - /** - * Assign targets to a given target tag id. - * - * @param targetTagId - * the ID of the target tag to add the targets - * @param assignedTargetRequestBodies - * a list of controller ids - * @return a list of assigned targets - */ - @RequestLine("POST " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING - + RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING) - @Headers("Content-Type: application/json") - TargetsRest assignTargets(@Param("targetTagId") final Long targetTagId, - final List assignedTargetRequestBodies); - - /** - * Unassign targets to a given target tag id. - * - * @param targetTagId - * the ID of the target tag to add the targets - */ - @RequestLine("DELETE " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING - + RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING) - void unassignTargets(@Param("targetTagId") final Long targetTagId); - - /** - * Unassign one target to a given target tag id. - * - * @param targetTagId - * the ID of the target tag to add the targets param - * @param controllerId - * the controller id - */ - @RequestLine("DELETE " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING - + RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING + "/{controllerId}") - void unassignTarget(@Param("targetTagId") final Long targetTagId, @Param("controllerId") final String controllerId); -} 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 new file mode 100644 index 000000000..27584b50a --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/Application.java @@ -0,0 +1,77 @@ +/** + * 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/ApplicationJsonRequestHeaderInterceptor.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ApplicationJsonRequestHeaderInterceptor.java new file mode 100644 index 000000000..75f3b0dd1 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ApplicationJsonRequestHeaderInterceptor.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.mgmt.client; + +import org.springframework.http.MediaType; + +import feign.RequestInterceptor; +import feign.RequestTemplate; + +/** + * An feign request interceptor to set the defined {@code Accept} and + * {@code Content-Type} headers for each request to {@code application/json}. + */ +public class ApplicationJsonRequestHeaderInterceptor implements RequestInterceptor { + + @Override + public void apply(final RequestTemplate template) { + template.header("Accept", MediaType.APPLICATION_JSON_VALUE); + template.header("Content-Type", MediaType.APPLICATION_JSON_VALUE); + } + +} 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 new file mode 100644 index 000000000..6d15bcc04 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.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.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 { + + private String url = "localhost:8080"; + private String username = "admin"; + 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/IgnoreMultipleConsumersProducersSpringMvcContract.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/IgnoreMultipleConsumersProducersSpringMvcContract.java new file mode 100644 index 000000000..c796aa019 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/IgnoreMultipleConsumersProducersSpringMvcContract.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.mgmt.client; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.netflix.feign.support.SpringMvcContract; + +import feign.MethodMetadata; + +/** + * Own implementation of the {@link SpringMvcContract} which catches the + * {@link IllegalStateException} which occurs due multiple produces and consumes + * values in the request-mapping + * annoation.https://github.com/spring-cloud/spring-cloud-netflix/issues/808 + */ +public class IgnoreMultipleConsumersProducersSpringMvcContract extends SpringMvcContract { + + private static final Logger LOGGER = LoggerFactory + .getLogger(IgnoreMultipleConsumersProducersSpringMvcContract.class); + + @Override + protected void processAnnotationOnMethod(final MethodMetadata data, final Annotation methodAnnotation, + final Method method) { + try { + super.processAnnotationOnMethod(data, methodAnnotation, method); + } catch (final IllegalStateException e) { + // ignore illegalstateexception here because it's thrown because of + // multiple consumers and produces, see + // https://github.com/spring-cloud/spring-cloud-netflix/issues/808 + LOGGER.trace(e.getMessage(), e); + } + } +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetResourceClient.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetResourceClient.java new file mode 100644 index 000000000..00a9b3fba --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetResourceClient.java @@ -0,0 +1,20 @@ +/** + * 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.rest.resource.api.DistributionSetRestApi; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the DistributionSet resource of the management API. + */ +@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/distributionsets") +public interface DistributionSetResourceClient extends DistributionSetRestApi { + +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTagResourceClient.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTagResourceClient.java new file mode 100644 index 000000000..ea9f5d28a --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTagResourceClient.java @@ -0,0 +1,20 @@ +/** + * 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.rest.resource.api.DistributionSetTagRestApi; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the DistributionSetTag resource of the management API. + */ +@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/distributionsettags") +public interface DistributionSetTagResourceClient extends DistributionSetTagRestApi { + +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTypeResourceClient.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTypeResourceClient.java new file mode 100644 index 000000000..08d40dfa5 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/DistributionSetTypeResourceClient.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.rest.resource.api.DistributionSetTypeRestApi; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the DistributionSetType resource of the management API. + * + */ +@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/distributionsettypes") +public interface DistributionSetTypeResourceClient extends DistributionSetTypeRestApi { + +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/RolloutResourceClient.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/RolloutResourceClient.java new file mode 100644 index 000000000..78b7413e7 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/RolloutResourceClient.java @@ -0,0 +1,20 @@ +/** + * 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.rest.resource.api.RolloutRestApi; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the Rollout resource of the management API. + */ +@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/rollouts") +public interface RolloutResourceClient extends RolloutRestApi { + +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleResourceClient.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleResourceClient.java new file mode 100644 index 000000000..88e664d78 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleResourceClient.java @@ -0,0 +1,20 @@ +/** + * 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.rest.resource.api.SoftwareModuleRestAPI; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the SoftwareModule resource of the management API. + */ +@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/softwaremodules") +public interface SoftwareModuleResourceClient extends SoftwareModuleRestAPI { + +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleTypeResourceClient.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleTypeResourceClient.java new file mode 100644 index 000000000..4896cb8d8 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/SoftwareModuleTypeResourceClient.java @@ -0,0 +1,20 @@ +/** + * 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.rest.resource.api.SoftwareModuleTypeRestApi; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the oftwareModuleType resource of the management API. + */ +@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/softwaremoduletypes") +public interface SoftwareModuleTypeResourceClient extends SoftwareModuleTypeRestApi { + +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetResourceClient.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetResourceClient.java new file mode 100644 index 000000000..a82aa5443 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetResourceClient.java @@ -0,0 +1,20 @@ +/** + * 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.rest.resource.api.TargetRestApi; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the Target resource of the management API. + */ +@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/targets") +public interface TargetResourceClient extends TargetRestApi { + +} diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetTagResourceClient.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetTagResourceClient.java new file mode 100644 index 000000000..fee30c686 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/TargetTagResourceClient.java @@ -0,0 +1,20 @@ +/** + * 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.rest.resource.api.TargetTagRestApi; +import org.springframework.cloud.netflix.feign.FeignClient; + +/** + * Client binding for the TargetTag resource of the management API. + */ +@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/targettags") +public interface TargetTagResourceClient extends TargetTagRestApi { + +} 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 new file mode 100644 index 000000000..c821b106c --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetBuilder.java @@ -0,0 +1,99 @@ +/** + * 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}. + * + * @author Jonathan Knoblauch + * + */ +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/DistributionSetTypeBuilder.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java new file mode 100644 index 000000000..e1da1f048 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.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.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 com.google.common.collect.Lists; + +/** + * + * Builder pattern for building {@link DistributionSetTypeRequestBodyPost}. + * + * @author Jonathan Knoblauch + * + */ +public class DistributionSetTypeBuilder { + + private String key; + private String name; + private final List mandatorymodules = Lists.newArrayList(); + private final List optionalmodules = Lists.newArrayList(); + + /** + * @param key + * the key of the distribution set type + * @return the builder itself + */ + public DistributionSetTypeBuilder key(final String key) { + this.key = key; + return this; + } + + /** + * @param name + * the name of the distribution set type + * @return the builder itself + */ + public DistributionSetTypeBuilder name(final String name) { + this.name = name; + return this; + } + + /** + * @param softwareModuleTypeIds + * the IDs of the software module types which should be mandatory + * for the distribution set type + * @return the builder itself + */ + public DistributionSetTypeBuilder mandatorymodules(final Long... softwareModuleTypeIds) { + for (final Long id : softwareModuleTypeIds) { + final SoftwareModuleTypeAssigmentRest softwareModuleTypeAssigmentRest = new SoftwareModuleTypeAssigmentRest(); + softwareModuleTypeAssigmentRest.setId(id); + this.mandatorymodules.add(softwareModuleTypeAssigmentRest); + } + return this; + } + + /** + * + * @param softwareModuleTypeIds + * the IDs of the software module types which should be optional + * for the distribution set type + * @return the builder itself + */ + public DistributionSetTypeBuilder optionalmodules(final Long... softwareModuleTypeIds) { + for (final Long id : softwareModuleTypeIds) { + final SoftwareModuleTypeAssigmentRest softwareModuleTypeAssigmentRest = new SoftwareModuleTypeAssigmentRest(); + softwareModuleTypeAssigmentRest.setId(id); + this.optionalmodules.add(softwareModuleTypeAssigmentRest); + } + return this; + } + + /** + * Builds a list with a single entry of + * {@link DistributionSetTypeRequestBodyPost} which can directly be used in + * the RESTful-API. + * + * @return a single entry list of {@link DistributionSetTypeRequestBodyPost} + */ + public List build() { + return Lists.newArrayList(doBuild(name, key)); + } + + /** + * 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. + * + * @param count + * the amount of distribution sets type 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, key + index)); + } + return bodyList; + + } + + private DistributionSetTypeRequestBodyPost doBuild(final String prefixName, final String prefixKey) { + final DistributionSetTypeRequestBodyPost body = new DistributionSetTypeRequestBodyPost(); + body.setKey(prefixKey); + body.setName(prefixName); + 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-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java new file mode 100644 index 000000000..bea0fd9a4 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java @@ -0,0 +1,115 @@ +/** + * 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 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; + +/** + * + * Builder pattern for building {@link RolloutRestRequestBody}. + * + * @author Jonathan Knoblauch + * + */ +public class RolloutBuilder { + + private String name; + private int groupSize; + private String targetFilterQuery; + private long distributionSetId; + private String successThreshold; + private String errorThreshold; + + /** + * @param name + * the name of the rollout + * @return the builder itself + */ + public RolloutBuilder name(final String name) { + this.name = name; + return this; + } + + /** + * @param groupSize + * the amount of groups the rollout should be split into + * @return the builder itself + */ + public RolloutBuilder groupSize(final int groupSize) { + this.groupSize = groupSize; + return this; + } + + /** + * @param targetFilterQuery + * the FIQL query language to filter targets to contain in the + * rollout + * @return the builder itself + */ + public RolloutBuilder targetFilterQuery(final String targetFilterQuery) { + this.targetFilterQuery = targetFilterQuery; + return this; + } + + /** + * @param distributionSetId + * the ID of the distribution set to assign to the target in the + * rollout + * @return the builder itself + */ + public RolloutBuilder distributionSetId(final long distributionSetId) { + this.distributionSetId = distributionSetId; + return this; + } + + /** + * @param successThreshold + * the threshold to be used to indicate if a deployment group is + * successful, to trigger the success action + * @return the builder itself + */ + public RolloutBuilder successThreshold(final String successThreshold) { + this.successThreshold = successThreshold; + return this; + } + + /** + * @param errorThreshold + * the threshold to be used to indicate if a deployment group is + * failing, to trigger the error action + * @return the builder itself + */ + public RolloutBuilder errorThreshold(final String errorThreshold) { + this.errorThreshold = errorThreshold; + return this; + } + + /** + * Builds the rollout rest body to creating a rollout. + * + * @return the rest request body for creating a rollout + */ + public RolloutRestRequestBody build() { + return doBuild(); + } + + private RolloutRestRequestBody doBuild() { + final RolloutRestRequestBody body = new RolloutRestRequestBody(); + 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)); + 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-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleAssigmentBuilder.java new file mode 100644 index 000000000..840f16182 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleAssigmentBuilder.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.mgmt.client.resource.builder; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleAssigmentRest; + +/** + * + * Builder pattern for building {@link SoftwareModuleAssigmentRest}. + * + * @author Jonathan Knoblauch + * + */ +public class SoftwareModuleAssigmentBuilder { + + private final List ids; + + public SoftwareModuleAssigmentBuilder() { + ids = new ArrayList(); + } + + /** + * @param id + * the id of the software module + * @return the builder itself + */ + public SoftwareModuleAssigmentBuilder id(final Long id) { + ids.add(id); + return this; + } + + /** + * Builds a list with a single entry of {@link SoftwareModuleAssigmentRest} + * which can directly be used in the RESTful-API. + * + * @return a single entry list of {@link SoftwareModuleAssigmentRest} + */ + public List build() { + final List softwareModuleAssigmentRestList = new ArrayList<>(); + for (final Long id : ids) { + final SoftwareModuleAssigmentRest softwareModuleAssigmentRest = new SoftwareModuleAssigmentRest(); + softwareModuleAssigmentRest.setId(id); + softwareModuleAssigmentRestList.add(softwareModuleAssigmentRest); + } + return softwareModuleAssigmentRestList; + } + +} 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 new file mode 100644 index 000000000..30b85d901 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleBuilder.java @@ -0,0 +1,101 @@ +/** + * 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}. + * + * @author Jonathan Knoblauch + * + */ +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/SoftwareModuleTypeBuilder.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java new file mode 100644 index 000000000..ce128d592 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java @@ -0,0 +1,101 @@ +/** + * 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.softwaremodule.SoftwareModuleRequestBodyPost; +import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPost; + +import com.google.common.collect.Lists; + +/** + * + * Builder pattern for building {@link SoftwareModuleRequestBodyPost}. + * + * @author Jonathan Knoblauch + * + */ +public class SoftwareModuleTypeBuilder { + + private String key; + private String name; + private String description; + private int maxAssignments; + + /** + * @param key + * the key of the software module type + * @return the builder itself + */ + public SoftwareModuleTypeBuilder key(final String key) { + this.key = key; + return this; + } + + /** + * @param name + * the name of the software module type + * @return the builder itself + */ + public SoftwareModuleTypeBuilder name(final String name) { + this.name = name; + return this; + } + + public SoftwareModuleTypeBuilder description(final String description) { + this.description = description; + return this; + } + + public SoftwareModuleTypeBuilder maxAssignments(final int maxAssignments) { + this.maxAssignments = maxAssignments; + return this; + } + + /** + * Builds a list with a single entry of + * {@link SoftwareModuleTypeRequestBodyPost} which can directly be used in + * the RESTful-API. + * + * @return a single entry list of {@link SoftwareModuleTypeRequestBodyPost} + */ + public List build() { + return Lists.newArrayList(doBuild(key, name)); + } + + /** + * 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. + * + * @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(key + index, name + index)); + } + return bodyList; + } + + private SoftwareModuleTypeRequestBodyPost doBuild(final String prefixKey, final String prefixName) { + final SoftwareModuleTypeRequestBodyPost body = new SoftwareModuleTypeRequestBodyPost(); + body.setKey(prefixKey); + body.setName(prefixName); + body.setDescription(description); + body.setMaxAssignments(maxAssignments); + return body; + } + +} \ No newline at end of file diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java new file mode 100644 index 000000000..f3888de54 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java @@ -0,0 +1,96 @@ +/** + * 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.tag.TagRequestBodyPut; + +import com.google.common.collect.Lists; + +/** + * Builder pattern for building {@link TagRequestBodyPut}. + * + * @author Jonathan Knoblauch + * + */ +public class TagBuilder { + + private String name; + private String description; + private String color; + + /** + * @param name + * the name of the tag + * @return the builder itself + */ + public TagBuilder name(final String name) { + this.name = name; + return this; + } + + /** + * @param description + * the description of the tag + * @return the builder itself + */ + public TagBuilder description(final String description) { + this.description = description; + return this; + } + + /** + * @param color + * the colour of the tag + * @return the builder itself + */ + public TagBuilder color(final String color) { + this.color = color; + return this; + } + + /** + * Builds a list with a single entry of {@link TagRequestBodyPut} which can + * directly be used in the RESTful-API. + * + * @return a single entry list of {@link TagRequestBodyPut} + */ + 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. + * + * @param count + * the amount of distribution sets body which should be created + * @return a list of {@link TagRequestBodyPut} + */ + 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 TagRequestBodyPut doBuild(final String prefixName) { + final TagRequestBodyPut body = new TagRequestBodyPut(); + body.setName(prefixName); + body.setDescription(description); + body.setColour(color); + 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 new file mode 100644 index 000000000..5123903d9 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java @@ -0,0 +1,98 @@ +/** + * 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}. + * + * @author Jonathan Knoblauch + * + */ +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/CreateStartedRolloutExample.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/CreateStartedRolloutExample.java new file mode 100644 index 000000000..35b0f31ea --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/CreateStartedRolloutExample.java @@ -0,0 +1,107 @@ +/** + * 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 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.builder.DistributionSetBuilder; +import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetTypeBuilder; +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.SoftwareModuleTypeBuilder; +import org.eclipse.hawkbit.mgmt.client.resource.builder.TargetBuilder; +import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest; +import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutResponseBody; +import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModulesRest; +import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypesRest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 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"; + + /* known distribution set type name and key */ + private static final String DS_MODULE_TYPE = "firmware"; + + @Autowired + private DistributionSetResourceClient distributionSetResource; + + @Autowired + private SoftwareModuleResourceClient softwareModuleResource; + + @Autowired + private TargetResourceClient targetResource; + + @Autowired + private RolloutResourceClient rolloutResource; + + @Autowired + private DistributionSetTypeResourceClient distributionSetTypeResource; + + @Autowired + private SoftwareModuleTypeResourceClient softwareModuleTypeResource; + + /** + * Run the Rollout scenario. + */ + public void run() { + + // create three SoftwareModuleTypes + final SoftwareModuleTypesRest createdSoftwareModuleTypes = softwareModuleTypeResource.createSoftwareModuleTypes( + new SoftwareModuleTypeBuilder().key(SM_MODULE_TYPE).name(SM_MODULE_TYPE).maxAssignments(1).build()) + .getBody(); + + // create one DistributionSetType + distributionSetTypeResource.createDistributionSetTypes(new DistributionSetTypeBuilder().key(DS_MODULE_TYPE) + .name(DS_MODULE_TYPE).mandatorymodules(createdSoftwareModuleTypes.get(0).getModuleId()).build()) + .getBody(); + + // create one DistributionSet + final DistributionSetsRest distributionSetsRest = distributionSetResource.createDistributionSets( + new DistributionSetBuilder().name("rollout-example").version("1.0.0").type(DS_MODULE_TYPE).build()) + .getBody(); + + // create three SoftwareModules + final SoftwareModulesRest softwareModulesRest = softwareModuleResource + .createSoftwareModules( + new SoftwareModuleBuilder().name("firmware").version("1.0.0").type(SM_MODULE_TYPE).build()) + .getBody(); + + // Assign SoftwareModule to DistributionSet + distributionSetResource.assignSoftwareModules(distributionSetsRest.get(0).getDsId(), + new SoftwareModuleAssigmentBuilder().id(softwareModulesRest.get(0).getModuleId()).build()); + + // create ten targets + targetResource.createTargets(new TargetBuilder().controllerId("00-FF-AA-0").name("00-FF-AA-0") + .description("Targets used for rollout example").buildAsList(10)); + + // create a Rollout + final RolloutResponseBody 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()) + .getBody(); + + // start the created Rollout + rolloutResource.start(rolloutResponseBody.getRolloutId(), false); + } + +} 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 new file mode 100644 index 000000000..5767ab9e7 --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/GettingStartedDefaultScenario.java @@ -0,0 +1,134 @@ +/** + * 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 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.DistributionSetsRest; +import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModulesRest; +import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypesRest; +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 = "gettingstarted"; + + /* 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 = "gettingstarted-example"; + + @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 SoftwareModuleTypesRest 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 DistributionSetsRest 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 DistributionSetsRest 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 DistributionSetsRest 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 SoftwareModulesRest 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 SoftwareModulesRest 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 SoftwareModulesRest 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 new file mode 100644 index 000000000..da0aa79dd --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/resources/application.properties @@ -0,0 +1,14 @@ +# +# 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.banner-mode=OFF \ No newline at end of file diff --git a/examples/hawkbit-mgmt-api-client/src/main/resources/logback.xml b/examples/hawkbit-mgmt-api-client/src/main/resources/logback.xml new file mode 100644 index 000000000..819566e0f --- /dev/null +++ b/examples/hawkbit-mgmt-api-client/src/main/resources/logback.xml @@ -0,0 +1,30 @@ + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + \ No newline at end of file diff --git a/examples/hawkbit-mgmt-api-client/src/test/java/org/eclipse/hawkbit/mgmt/api/client/DistributionSetTagTest.java b/examples/hawkbit-mgmt-api-client/src/test/java/org/eclipse/hawkbit/mgmt/api/client/DistributionSetTagTest.java deleted file mode 100644 index 17384c211..000000000 --- a/examples/hawkbit-mgmt-api-client/src/test/java/org/eclipse/hawkbit/mgmt/api/client/DistributionSetTagTest.java +++ /dev/null @@ -1,186 +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.api.client; - -import static org.fest.assertions.api.Assertions.assertThat; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.hawkbit.app.Start; -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.DistributionSetsRest; -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.rest.resource.model.tag.TagsRest; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; -import org.springframework.boot.SpringApplication; -import org.springframework.context.annotation.Description; - -import ru.yandex.qatools.allure.annotations.Features; -import ru.yandex.qatools.allure.annotations.Stories; -import feign.Feign; -import feign.Logger; -import feign.auth.BasicAuthRequestInterceptor; -import feign.jackson.JacksonDecoder; -import feign.jackson.JacksonEncoder; - -@Features("Example Tests - Management RESTful API Client") -@Stories("DistrubutionSet Tag Resource") -public class DistributionSetTagTest { - - private DistrubutionSetTagResource distrubutionSetTagResource; - - private static List assignedTargetRequestBodies; - - @BeforeClass - public static void startupServer() { - SpringApplication.run(Start.class, new String[0]); - createTargetsAssignment(); - assignedTargetRequestBodies.add(new AssignedDistributionSetRequestBody().setDistributionSetId(100L)); - } - - @Before - public void setup() { - this.distrubutionSetTagResource = createDistrubutionSetTagResource(); - } - - // disabled as this runs not on CI environments. - @Test - @Description("Simple request of distrubutionset tag by ID") - @Ignore - public void getDistributionSetTag() { - final TagsRest result = createDistributionSetTags(2); - - assertThat(distrubutionSetTagResource.getDistributionSetTag(result.get(0).getTagId()).getName()).isEqualTo( - "Tag0"); - - deleteDistributionSets(result); - } - - // disabled as this runs not on CI environments. - @Test - @Description("Simple update of a distrubutionset tag") - @Ignore - public void updateDistributionSetTag() { - final TagsRest created = createDistributionSetTags(10); - - distrubutionSetTagResource.updateDistributionSetTag(created.get(0).getTagId(), new TagRequestBodyPut() - .setDescription("Test").setName("Test").setColour("Green")); - - final TagRest targetTag = distrubutionSetTagResource.getDistributionSetTag(created.get(0).getTagId()); - assertThat(targetTag.getName()).isEqualTo("Test"); - assertThat(targetTag.getDescription()).isEqualTo("Test"); - assertThat(targetTag.getColour()).isEqualTo("Green"); - - deleteDistributionSets(created); - } - - // disabled as this runs not on CI environments. - @Test - @Description("Simple request of all assigned distrubutionsets by a distrubutionset tag.") - @Ignore - public void getDistributionSetByTagId() { - final TagsRest created = createDistributionSetTags(10); - distrubutionSetTagResource.assignDistributionSets(created.get(2).getTagId(), assignedTargetRequestBodies); - - final DistributionSetsRest distributionSetsRest = distrubutionSetTagResource - .getAssignedDistributionSets(created.get(2).getTagId()); - assertThat(distributionSetsRest).hasSize(5); - - distrubutionSetTagResource.unassignDistributionSets(created.get(2).getTagId()); - deleteDistributionSets(created); - } - - @Test - @Description("Toggle request to unassigned all assigned distrubutionset and assign all unassigned distrubutionset.") - @Ignore - public void toggleTagAssignment() { - final TagsRest created = createDistributionSetTags(10); - final Long id = created.get(2).getTagId(); - - distrubutionSetTagResource.assignDistributionSets(id, assignedTargetRequestBodies); - distrubutionSetTagResource.unassignDistributionSet(id, assignedTargetRequestBodies.get(0) - .getDistributionSetId()); - - DistributionSetTagAssigmentResultRest assigmentResultRest = distrubutionSetTagResource.toggleTagAssignment(id, - assignedTargetRequestBodies); - - final TagRest targetTag = distrubutionSetTagResource.getDistributionSetTag(created.get(2).getTagId()); - assertThat(assigmentResultRest.getAssignedDistributionSets()).hasSize(1); - assertThat(assigmentResultRest.getUnassignedDistributionSets()).hasSize(0); - - assigmentResultRest = distrubutionSetTagResource.toggleTagAssignment(id, assignedTargetRequestBodies); - assertThat(assigmentResultRest.getAssignedDistributionSets()).hasSize(0); - assertThat(assigmentResultRest.getUnassignedDistributionSets()).hasSize(5); - - distrubutionSetTagResource.unassignDistributionSets(targetTag.getTagId()); - deleteDistributionSets(created); - } - - private void deleteDistributionSets(final List tags) { - for (final TagRest tag : tags) { - distrubutionSetTagResource.deleteDistributionSetTag(tag.getTagId()); - } - } - - private TagsRest createDistributionSetTags(final int number) { - - final List tags = new ArrayList<>(); - for (int i = 0; i < number; i++) { - tags.add(new TagRequestBodyPut().setDescription("Tag " + i).setName("Tag" + i).setColour("Red")); - } - - final TagsRest result = distrubutionSetTagResource.createDistributionSetTags(tags); - - assertThat(result).hasSize(number); - return result; - } - - private DistrubutionSetTagResource createDistrubutionSetTagResource() { - final DistrubutionSetTagResource distrubutionSetTagResource = Feign.builder().logger(new Logger.ErrorLogger()) - .logLevel(Logger.Level.BASIC).decoder(new JacksonDecoder()).encoder(new JacksonEncoder()) - .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) - .target(DistrubutionSetTagResource.class, "http://localhost:8080"); - return distrubutionSetTagResource; - } - - private static void createTargetsAssignment() { - - final List sets = new ArrayList<>(); - assignedTargetRequestBodies = new ArrayList<>(); - for (int i = 0; i < 5; i++) { - final DistributionSetRequestBodyPost bodyPost = (DistributionSetRequestBodyPost) new DistributionSetRequestBodyPost() - .setName("Ds" + i).setDescription("Ds" + i).setVersion("" + i); - sets.add(bodyPost); - } - - final DistributionSetsRest result = createDistributionSetResource().createDistributionSets(sets); - for (final DistributionSetRest rest : result) { - assignedTargetRequestBodies.add(new AssignedDistributionSetRequestBody().setDistributionSetId(rest - .getDsId())); - } - - } - - private static DistributionSetResource createDistributionSetResource() { - final DistributionSetResource distributionSetResource = Feign.builder().logger(new Logger.ErrorLogger()) - .logLevel(Logger.Level.BASIC).decoder(new JacksonDecoder()).encoder(new JacksonEncoder()) - .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) - .target(DistributionSetResource.class, "http://localhost:8080"); - return distributionSetResource; - } - -} diff --git a/examples/hawkbit-mgmt-api-client/src/test/java/org/eclipse/hawkbit/mgmt/api/client/TargetTagTest.java b/examples/hawkbit-mgmt-api-client/src/test/java/org/eclipse/hawkbit/mgmt/api/client/TargetTagTest.java deleted file mode 100644 index 10f18b704..000000000 --- a/examples/hawkbit-mgmt-api-client/src/test/java/org/eclipse/hawkbit/mgmt/api/client/TargetTagTest.java +++ /dev/null @@ -1,182 +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.api.client; - -import static org.fest.assertions.api.Assertions.assertThat; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.hawkbit.app.Start; -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.TagsRest; -import org.eclipse.hawkbit.rest.resource.model.tag.TargetTagAssigmentResultRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; -import org.springframework.boot.SpringApplication; -import org.springframework.context.annotation.Description; - -import ru.yandex.qatools.allure.annotations.Features; -import ru.yandex.qatools.allure.annotations.Stories; -import feign.Feign; -import feign.Logger; -import feign.auth.BasicAuthRequestInterceptor; -import feign.jackson.JacksonDecoder; -import feign.jackson.JacksonEncoder; - -@Features("Example Tests - Management RESTful API Client") -@Stories("Target Tag Resource") -public class TargetTagTest { - - private TargetTagResource targetTagResource; - - private static List assignedTargetRequestBodies; - - @BeforeClass - public static void startupServer() { - SpringApplication.run(Start.class, new String[0]); - createTargetsAssignment(); - assignedTargetRequestBodies.add(new AssignedTargetRequestBody().setControllerId("NotExist")); - } - - @Before - public void setup() { - this.targetTagResource = createTargetTagResource(); - } - - // disabled as this runs not on CI environments. - @Test - @Description("Simple request of target tag by ID") - @Ignore - public void getTargetTag() { - final TagsRest result = createTargetTags(2); - - assertThat(targetTagResource.getTargetTag(result.get(0).getTagId()).getName()).isEqualTo("Tag0"); - - deleteTargets(result); - } - - // disabled as this runs not on CI environments. - @Test - @Description("Simple update of a target tag") - @Ignore - public void updateTargetTag() { - final TagsRest created = createTargetTags(10); - - targetTagResource.updateTagretTag(created.get(0).getTagId(), new TagRequestBodyPut().setDescription("Test") - .setName("Test").setColour("Green")); - - final TagRest targetTag = targetTagResource.getTargetTag(created.get(0).getTagId()); - assertThat(targetTag.getName()).isEqualTo("Test"); - assertThat(targetTag.getDescription()).isEqualTo("Test"); - assertThat(targetTag.getColour()).isEqualTo("Green"); - - deleteTargets(created); - } - - // disabled as this runs not on CI environments. - @Test - @Description("Simple request of all assigned targets by a target tag.") - @Ignore - public void getTargetsByTargetTagId() { - final TagsRest created = createTargetTags(10); - final Long tagId = created.get(2).getTagId(); - targetTagResource.assignTargets(tagId, assignedTargetRequestBodies); - - final TagRest targetTag = targetTagResource.getTargetTag(tagId); - assertThat(targetTagResource.getAssignedTargets(tagId)).hasSize(5); - - targetTagResource.unassignTargets(targetTag.getTagId()); - deleteTargets(created); - } - - @Test - @Description("Toggle request to unassigned all assigned targets and assign all unassigned targets.") - @Ignore - public void toggleTagAssignment() { - final TagsRest created = createTargetTags(10); - final Long id = created.get(2).getTagId(); - - targetTagResource.assignTargets(id, assignedTargetRequestBodies); - targetTagResource.unassignTarget(id, assignedTargetRequestBodies.get(0).getControllerId()); - - TargetTagAssigmentResultRest assigmentResultRest = targetTagResource.toggleTagAssignment(id, - assignedTargetRequestBodies); - - final TagRest targetTag = targetTagResource.getTargetTag(created.get(2).getTagId()); - assertThat(assigmentResultRest.getAssignedTargets()).hasSize(1); - assertThat(assigmentResultRest.getUnassignedTargets()).hasSize(0); - - assigmentResultRest = targetTagResource.toggleTagAssignment(id, assignedTargetRequestBodies); - assertThat(assigmentResultRest.getAssignedTargets()).hasSize(0); - assertThat(assigmentResultRest.getUnassignedTargets()).hasSize(5); - - targetTagResource.unassignTargets(targetTag.getTagId()); - deleteTargets(created); - } - - private void deleteTargets(final List tags) { - for (final TagRest tag : tags) { - targetTagResource.deleteTargetTag(tag.getTagId()); - } - } - - private TagsRest createTargetTags(final int number) { - - final List tags = new ArrayList<>(); - for (int i = 0; i < number; i++) { - tags.add(new TagRequestBodyPut().setDescription("Tag " + i).setName("Tag" + i).setColour("Red")); - } - - final TagsRest result = targetTagResource.createTargetTag(tags); - - assertThat(result).hasSize(number); - return result; - } - - private TargetTagResource createTargetTagResource() { - final TargetTagResource targetResource = Feign.builder().logger(new Logger.ErrorLogger()) - .logLevel(Logger.Level.BASIC).decoder(new JacksonDecoder()).encoder(new JacksonEncoder()) - .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) - .target(TargetTagResource.class, "http://localhost:8080"); - return targetResource; - } - - private static void createTargetsAssignment() { - - final List targets = new ArrayList<>(); - assignedTargetRequestBodies = new ArrayList<>(); - for (int i = 0; i < 5; i++) { - - targets.add(new TargetRequestBody().setControllerId("test" + i).setName("testDevice")); - } - - final TargetsRest result = createTargetResource().createTargets(targets); - for (final TargetRest rest : result) { - assignedTargetRequestBodies.add(new AssignedTargetRequestBody().setControllerId(rest.getControllerId())); - } - - } - - private static TargetResource createTargetResource() { - final TargetResource targetResource = Feign.builder().logger(new Logger.ErrorLogger()) - .logLevel(Logger.Level.BASIC).decoder(new JacksonDecoder()).encoder(new JacksonEncoder()) - .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) - .target(TargetResource.class, "http://localhost:8080"); - return targetResource; - } - -} diff --git a/examples/hawkbit-mgmt-api-client/src/test/java/org/eclipse/hawkbit/mgmt/api/client/TargetTest.java b/examples/hawkbit-mgmt-api-client/src/test/java/org/eclipse/hawkbit/mgmt/api/client/TargetTest.java deleted file mode 100644 index 745b119f6..000000000 --- a/examples/hawkbit-mgmt-api-client/src/test/java/org/eclipse/hawkbit/mgmt/api/client/TargetTest.java +++ /dev/null @@ -1,119 +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.api.client; - -import static org.fest.assertions.api.Assertions.assertThat; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.hawkbit.app.Start; -import org.eclipse.hawkbit.rest.resource.model.target.TargetPagedList; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody; -import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; -import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; -import org.springframework.boot.SpringApplication; -import org.springframework.context.annotation.Description; - -import feign.Feign; -import feign.Logger; -import feign.auth.BasicAuthRequestInterceptor; -import feign.jackson.JacksonDecoder; -import feign.jackson.JacksonEncoder; -import ru.yandex.qatools.allure.annotations.Features; -import ru.yandex.qatools.allure.annotations.Stories; - -@Features("Example Tests - Management RESTful API Client") -@Stories("Target Resource") -public class TargetTest { - - @BeforeClass - public static void startupServer() { - SpringApplication.run(Start.class, new String[0]); - } - - // disabled as this runs not on CI environments. - @Test - @Description("Simple request of target by ID") - @Ignore - public void getTarget() { - final TargetResource targetResource = createTargetResource(); - final TargetsRest result = createTargets(targetResource, 1); - - assertThat(targetResource.getTarget("test0").getName()).isEqualTo("testDevice"); - - deleteTargets(targetResource, result); - } - - // disabled as this runs not on CI environments. - @Test - @Description("Simple request of all targets with defined page sizing information (i.e. offset and limit).") - @Ignore - public void getTargetsAsPagedListWithDefinedPageSizing() { - final TargetResource targetResource = createTargetResource(); - final TargetsRest created = createTargets(targetResource, 20); - - final TargetPagedList queryResult = targetResource.getTargets(0, 10); - - assertThat(queryResult.getContent()).hasSize(10); - assertThat(queryResult.getTotal()).isEqualTo(20); - assertThat(queryResult.getSize()).isEqualTo(10); - - deleteTargets(targetResource, created); - } - - // disabled as this runs not on CI environments. - @Test - @Description("Simple request of all targets with defualt paging parameters.") - @Ignore - public void getTargetsAsPagedListWithDefaultPageSizing() { - final TargetResource targetResource = createTargetResource(); - final TargetsRest created = createTargets(targetResource, 20); - - final TargetPagedList queryResult = targetResource.getTargets(); - - assertThat(queryResult.getContent()).hasSize(20); - assertThat(queryResult.getTotal()).isEqualTo(20); - assertThat(queryResult.getSize()).isEqualTo(20); - - deleteTargets(targetResource, created); - } - - private void deleteTargets(final TargetResource targetResource, final List targets) { - for (final TargetRest targetRest : targets) { - targetResource.deleteTarget(targetRest.getControllerId()); - } - } - - private TargetsRest createTargets(final TargetResource targetResource, final int number) { - - final List targets = new ArrayList<>(); - for (int i = 0; i < number; i++) { - - targets.add(new TargetRequestBody().setControllerId("test" + i).setName("testDevice")); - } - - final TargetsRest result = targetResource.createTargets(targets); - - assertThat(result).hasSize(number); - return result; - } - - private TargetResource createTargetResource() { - final TargetResource targetResource = Feign.builder().logger(new Logger.ErrorLogger()) - .logLevel(Logger.Level.BASIC).decoder(new JacksonDecoder()).encoder(new JacksonEncoder()) - .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) - .target(TargetResource.class, "http://localhost:8080"); - return targetResource; - } - -} 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 1b4daaf66..0a696fdb6 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 @@ -51,7 +51,16 @@ public enum TargetFields implements FieldNameProvider { */ ATTRIBUTE("targetInfo.controllerAttributes", true), + /** + * distribution sets which is assigned to the target. + */ ASSIGNEDDS("assignedDistributionSet", "name", "version"), + + /** + * distribution sets which is installed on the target. + */ + INSTALLEDDS("targetInfo.installedDistributionSet", "name", "version"), + /** * The tags field. */ 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 8921e368c..f8aed4f86 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 @@ -298,20 +298,7 @@ public class AmqpMessageHandlerService { */ private void updateActionStatus(final Message message) { final ActionUpdateStatus actionUpdateStatus = convertMessage(message, ActionUpdateStatus.class); - final Long actionId = actionUpdateStatus.getActionId(); - LOG.debug("Target notifies intermediate about action {} with status {}.", actionId, actionUpdateStatus - .getActionStatus().name()); - - if (actionId == null) { - logAndThrowMessageError(message, "Invalid message no action id"); - } - - final Action action = controllerManagement.findActionWithDetails(actionId); - - if (action == null) { - logAndThrowMessageError(message, "Got intermediate notification about action " + actionId - + " but action does not exist"); - } + final Action action = checkActionExist(message, actionUpdateStatus); final ActionStatus actionStatus = new ActionStatus(); final List messageText = actionUpdateStatus.getMessage(); @@ -362,6 +349,29 @@ public class AmqpMessageHandlerService { } } + /** + * @param message + * @param actionUpdateStatus + * @return + */ + private Action checkActionExist(final Message message, final ActionUpdateStatus actionUpdateStatus) { + final Long actionId = actionUpdateStatus.getActionId(); + LOG.debug("Target notifies intermediate about action {} with status {}.", actionId, actionUpdateStatus + .getActionStatus().name()); + + if (actionId == null) { + logAndThrowMessageError(message, "Invalid message no action id"); + } + + final Action action = controllerManagement.findActionWithDetails(actionId); + + if (action == null) { + logAndThrowMessageError(message, "Got intermediate notification about action " + actionId + + " but action does not exist"); + } + return action; + } + private void handleCancelRejected(final Message message, final Action action, final ActionStatus actionStatus) { if (action.isCancelingOrCanceled()) { diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentficationTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentficationTest.java index 5a77c5fce..1d962907b 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentficationTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentficationTest.java @@ -45,7 +45,7 @@ import ru.yandex.qatools.allure.annotations.Stories; /** * - * + * Test Amqp controller authentfication. */ @Features("AMQP Authenfication Test") @Stories("Tests the authenfication") @@ -86,24 +86,34 @@ public class AmqpControllerAuthentficationTest { amqpMessageHandlerService.setAuthenticationManager(authenticationManager); } - @Test(expected = BadCredentialsException.class) + @Test @Description("Tests authentication manager without principal") public void testAuthenticationeBadCredantialsWithoutPricipal() { final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345"); - authenticationManager.doAuthenticate(securityToken); - fail(); + try { + authenticationManager.doAuthenticate(securityToken); + fail("BadCredentialsException was excepeted since principal was missing"); + } catch (final BadCredentialsException exception) { + // test ok - exception was excepted + } + } - @Test(expected = BadCredentialsException.class) - @Description("Tests authentication manager without wrong credential") + @Test + @Description("Tests authentication manager without wrong credential") public void testAuthenticationBadCredantialsWithWrongCredential() { final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345"); when(systemManagement.getConfigurationValue( eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), any())) .thenReturn(Boolean.TRUE); securityToken.getHeaders().put(TenantSecruityToken.AUTHORIZATION_HEADER, "TargetToken 12" + CONTROLLLER_ID); - authenticationManager.doAuthenticate(securityToken); - fail(); + try { + authenticationManager.doAuthenticate(securityToken); + fail("BadCredentialsException was excepeted due to wrong credential"); + } catch (final BadCredentialsException exception) { + // test ok - exception was excepted + } + } @Test diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java index 6acf212ee..e2d31a04c 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java @@ -161,7 +161,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { @Override protected Map getVendorProperties() { - final Map properties = new HashMap(); + 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 diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeries.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeries.java index 97623d9d0..39c8f5723 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeries.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeries.java @@ -8,19 +8,22 @@ */ package org.eclipse.hawkbit.report.model; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; /** * A data report series which contains a list of {@link DataReportSeriesItem}. - * + * * * * @param * the type of the report series item */ -public class DataReportSeries extends AbstractReportSeries { +public class DataReportSeries extends AbstractReportSeries { + + private static final long serialVersionUID = 1L; private final List> data = new ArrayList<>(); @@ -46,7 +49,7 @@ public class DataReportSeries extends AbstractReportSeries { } private void setData(final List> values) { - this.data.clear(); + data.clear(); data.addAll(values); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeriesItem.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeriesItem.java index 3369ef1c0..492e27e1e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeriesItem.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/DataReportSeriesItem.java @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.report.model; +import java.io.Serializable; + /** * An data report series item which contains a type and a value. * @@ -16,8 +18,9 @@ package org.eclipse.hawkbit.report.model; * @param * the type of the report series item */ -public class DataReportSeriesItem { +public class DataReportSeriesItem implements Serializable { + private static final long serialVersionUID = 1L; private final T type; private final Number data; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/InnerOuterDataReportSeries.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/InnerOuterDataReportSeries.java index 1568847de..b63935b39 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/InnerOuterDataReportSeries.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/report/model/InnerOuterDataReportSeries.java @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.report.model; +import java.io.Serializable; + /** * A double data series which contains an inner and an outer series ideal for * showing donut charts. @@ -17,7 +19,7 @@ package org.eclipse.hawkbit.report.model; * @param * The type parameter for the report series data */ -public class InnerOuterDataReportSeries { +public class InnerOuterDataReportSeries { private final DataReportSeries innerSeries; private final DataReportSeries outerSeries; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java index 844bbd097..e4a1e5e6b 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java @@ -15,7 +15,6 @@ import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.validation.constraints.NotNull; @@ -212,14 +211,9 @@ public class ControllerManagement implements EnvironmentAware { @Modifying @Transactional @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - public Target findOrRegisterTargetIfItDoesNotexist(@NotNull final String targetid, final URI address) { - final Specification spec = new Specification() { - @Override - public Predicate toPredicate(final Root targetRoot, final CriteriaQuery query, - final CriteriaBuilder cb) { - return cb.equal(targetRoot.get(Target_.controllerId), targetid); - } - }; + 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); @@ -229,9 +223,9 @@ public class ControllerManagement implements EnvironmentAware { target.setName(targetid); return targetManagement.createTarget(target, TargetUpdateStatus.REGISTERED, System.currentTimeMillis(), address); - } else { - return updateLastTargetQuery(target.getTargetInfo(), address).getTarget(); } + + return updateLastTargetQuery(target.getTargetInfo(), address).getTarget(); } /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java index 0a3838354..d22a77f75 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java @@ -22,10 +22,6 @@ 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.Predicate; -import javax.persistence.criteria.Root; import javax.validation.constraints.NotNull; import org.eclipse.hawkbit.eventbus.event.DistributionSetTagAssigmentResultEvent; @@ -53,13 +49,13 @@ 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.domain.Specifications; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; @@ -203,7 +199,8 @@ public class DistributionSetManagement { } final DistributionSetTagAssigmentResult resultAssignment = result; - afterCommit.afterCommit(() -> eventBus.post(new DistributionSetTagAssigmentResultEvent(resultAssignment))); + afterCommit + .afterCommit(() -> eventBus.post(new DistributionSetTagAssigmentResultEvent(resultAssignment))); // no reason to persist the tag entityManager.detach(myTag); @@ -263,7 +260,7 @@ public class DistributionSetManagement { @Transactional @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) public void deleteDistributionSet(@NotNull final DistributionSet set) { - this.deleteDistributionSet(set.getId()); + deleteDistributionSet(set.getId()); } /** @@ -321,14 +318,10 @@ public class DistributionSetManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public DistributionSet createDistributionSet(@NotNull final DistributionSet dSet) { prepareDsSave(dSet); - if (dSet.getType() == null) { dSet.setType(systemManagement.getTenantMetadata().getDefaultDsType()); } - - final DistributionSet result = distributionSetRepository.save(dSet); - - return result; + return distributionSetRepository.save(dSet); } private void prepareDsSave(final DistributionSet dSet) { @@ -400,7 +393,7 @@ public class DistributionSetManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public DistributionSet unassignSoftwareModule(@NotNull final DistributionSet ds, final SoftwareModule softwareModule) { - final Set softwareModules = new HashSet(); + final Set softwareModules = new HashSet<>(); softwareModules.add(softwareModule); ds.removeModule(softwareModule); checkDistributionSetSoftwareModulesIsAllowedToModify(ds, softwareModules); @@ -491,20 +484,11 @@ public class DistributionSetManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) private DistributionSet findDistributionSetsByFiltersAndInstalledOrAssignedTarget( final DistributionSetFilter distributionSetFilter) { - final List> specList = buildDistributionSetSpecifications(distributionSetFilter); - - Specifications specs = null; - if (!specList.isEmpty()) { - specs = Specifications.where(specList.get(0)); + if (specList == null || specList.isEmpty()) { + return null; } - if (specList.size() > 1) { - specList.remove(0); - for (final Specification s : specList) { - specs = specs.and(s); - } - } - return distributionSetRepository.findOne(specs); + return distributionSetRepository.findOne(SpecificationsBuilder.combineWithAnd(specList)); } /** @@ -531,7 +515,7 @@ public class DistributionSetManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) public Page findDistributionSetsAll(@NotNull final Pageable pageReq, final Boolean deleted, final Boolean complete) { - final List> specList = new ArrayList>(); + final List> specList = new ArrayList<>(); if (deleted != null) { final Specification spec = DistributionSetSpecification.isDeleted(deleted); @@ -563,7 +547,7 @@ public class DistributionSetManagement { @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>(); + final List> specList = new ArrayList<>(); if (deleted != null) { specList.add(DistributionSetSpecification.isDeleted(deleted)); } @@ -635,17 +619,6 @@ public class DistributionSetManagement { return new PageImpl<>(resultSet, pageable, findDistributionSetsByFilters.getTotalElements()); } - private Long countDistributionSetByCriteriaAPI(@NotEmpty final List> specList) { - Specifications specs = Specifications.where(specList.get(0)); - if (specList.size() > 1) { - for (final Specification s : specList.subList(1, specList.size())) { - specs = specs.and(s); - } - } - - return distributionSetRepository.count(specs); - } - /** * Find distribution set by name and version. * @@ -689,12 +662,12 @@ public class DistributionSetManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) public Long countDistributionSetsAll() { - final List> specList = new ArrayList>(); + final List> specList = new ArrayList<>(); final Specification spec = DistributionSetSpecification.isDeleted(Boolean.FALSE); specList.add(spec); - return countDistributionSetByCriteriaAPI(specList); + return distributionSetRepository.count(SpecificationsBuilder.combineWithAnd(specList)); } /** @@ -869,17 +842,10 @@ public class DistributionSetManagement { public Page findDistributionSetMetadataByDistributionSetId( @NotNull final Long distributionSetId, @NotNull final Pageable pageable) { - return distributionSetMetadataRepository.findAll(new Specification() { - @Override - public Predicate toPredicate(final Root root, final CriteriaQuery query, - final CriteriaBuilder cb) { - - final Predicate predicate = cb.equal( - root.get(DistributionSetMetadata_.distributionSet).get(DistributionSet_.id), distributionSetId); - - return predicate; - } - }, pageable); + return distributionSetMetadataRepository.findAll( + (Specification) (root, query, cb) -> cb.equal( + root.get(DistributionSetMetadata_.distributionSet).get(DistributionSet_.id), distributionSetId), + pageable); } @@ -899,14 +865,14 @@ public class DistributionSetManagement { public Page findDistributionSetMetadataByDistributionSetId( @NotNull final Long distributionSetId, @NotNull final Specification spec, @NotNull final Pageable pageable) { - return distributionSetMetadataRepository.findAll(new Specification() { - @Override - public Predicate toPredicate(final Root root, final CriteriaQuery query, - final CriteriaBuilder cb) { - return cb.and(cb.equal(root.get(DistributionSetMetadata_.distributionSet).get(DistributionSet_.id), - distributionSetId), spec.toPredicate(root, query, cb)); - } - }, 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); } /** @@ -956,7 +922,7 @@ public class DistributionSetManagement { /** * Checking Distribution Set is already using while assign Software module. - * + * * @param distributionSet * @param softwareModules */ @@ -969,9 +935,9 @@ public class DistributionSetManagement { private List> buildDistributionSetSpecifications( final DistributionSetFilter distributionSetFilter) { - final List> specList = new ArrayList>(); + final List> specList = new ArrayList<>(); - Specification spec = null; + Specification spec; if (null != distributionSetFilter.getIsComplete()) { spec = DistributionSetSpecification.isCompleted(distributionSetFilter.getIsComplete()); @@ -1053,21 +1019,12 @@ public class DistributionSetManagement { */ private Page findByCriteriaAPI(@NotNull final Pageable pageable, final List> specList) { - Specifications specs = null; - if (!specList.isEmpty()) { - specs = Specifications.where(specList.get(0)); - } - if (specList.size() > 1) { - for (final Specification s : specList.subList(1, specList.size())) { - specs = specs.and(s); - } + + if (specList == null || specList.isEmpty()) { + return distributionSetRepository.findAll(pageable); } - if (specs == null) { - return distributionSetRepository.findAll(pageable); - } else { - return distributionSetRepository.findAll(specs, pageable); - } + return distributionSetRepository.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable); } private void checkAndThrowAlreadyIfDistributionSetMetadataExists(final DsMetadataCompositeKey metadataId) { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java index 801f6c80d..8f87f9209 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java @@ -213,8 +213,8 @@ public class ReportManagement { * count */ @Cacheable("targetsCreatedOverPeriod") - public DataReportSeries targetsCreatedOverPeriod(final DateType dateType, final LocalDateTime from, - final LocalDateTime to) { + public DataReportSeries targetsCreatedOverPeriod(final DateType dateType, + final LocalDateTime from, final LocalDateTime to) { final Query createNativeQuery = entityManager .createNativeQuery(getTargetsCreatedQueryTemplate(dateType, from, to)); final List resultList = createNativeQuery.getResultList(); @@ -223,8 +223,7 @@ public class ReportManagement { .map(r -> new DataReportSeriesItem<>(dateType.format((String) r[0]), ((Number) r[1]).longValue())) .collect(Collectors.toList()); - final DataReportSeries report = new DataReportSeries<>("CreatedTargets", reportItems); - return report; + return new DataReportSeries<>("CreatedTargets", reportItems); } private String getTargetsCreatedQueryTemplate(final DateType dateType, final LocalDateTime from, @@ -276,8 +275,8 @@ public class ReportManagement { * count */ @Cacheable("feedbackReceivedOverTime") - public DataReportSeries feedbackReceivedOverTime(final DateType dateType, final LocalDateTime from, - final LocalDateTime to) { + public DataReportSeries feedbackReceivedOverTime(final DateType dateType, + final LocalDateTime from, final LocalDateTime to) { final Query createNativeQuery = entityManager .createNativeQuery(getFeedbackReceivedQueryTemplate(dateType, from, to)); final List resultList = createNativeQuery.getResultList(); @@ -286,8 +285,7 @@ public class ReportManagement { .map(r -> new DataReportSeriesItem<>(dateType.format((String) r[0]), ((Number) r[1]).longValue())) .collect(Collectors.toList()); - final DataReportSeries report = new DataReportSeries<>("FeedbackRecieved", reportItems); - return report; + return new DataReportSeries<>("FeedbackRecieved", reportItems); } /** @@ -433,7 +431,7 @@ public class ReportManagement { } private DataReportSeriesItem toItem() { - return new DataReportSeriesItem(name.getName() != null ? name.getName() : "misc", count); + return new DataReportSeriesItem<>(name.getName() != null ? name.getName() : "misc", count); } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java index e98439b57..54ff37e87 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java @@ -245,8 +245,9 @@ public class RolloutGroupManagement { JoinType.LEFT); final Root countQueryFrom = countQuery.distinct(true).from(RolloutTargetGroup.class); - countQuery - .select(cb.count(countQueryFrom.join(RolloutTargetGroup_.target).join(Target_.actions, JoinType.LEFT))) + countQueryFrom.join(RolloutTargetGroup_.target); + countQueryFrom.join(RolloutTargetGroup_.actions, JoinType.LEFT); + countQuery.select(cb.count(countQueryFrom)) .where(cb.equal(countQueryFrom.get(RolloutTargetGroup_.rolloutGroup), rolloutGroup)); final Long totalCount = entityManager.createQuery(countQuery).getSingleResult(); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java index 0d3bc62c6..1573048ec 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java @@ -552,7 +552,7 @@ public class RolloutManagement { if (updated == 0) { // nothing to check, maybe another instance already checked in // between - LOGGER.info("No rolloutcheck necessary for current scheduled check {}, next check at {}", lastCheck, + LOGGER.debug("No rolloutcheck necessary for current scheduled check {}, next check at {}", lastCheck, lastCheck + delayBetweenChecks); return; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java index 98cb1f418..1f610d29c 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java @@ -40,6 +40,7 @@ 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; @@ -48,7 +49,6 @@ 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.domain.Specifications; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; @@ -198,7 +198,7 @@ public class SoftwareManagement { /** * retrieves the {@link SoftwareModule}s by their {@link SoftwareModuleType} * . - * + * * @param pageable * page parameters * @param type @@ -209,7 +209,7 @@ public class SoftwareManagement { public Slice findSoftwareModulesByType(@NotNull final Pageable pageable, @NotNull final SoftwareModuleType type) { - final List> specList = new ArrayList>(); + final List> specList = new ArrayList<>(); Specification spec = SoftwareModuleSpecification.equalType(type); specList.add(spec); @@ -230,7 +230,7 @@ public class SoftwareManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) public Long countSoftwareModulesByType(@NotNull final SoftwareModuleType type) { - final List> specList = new ArrayList>(); + final List> specList = new ArrayList<>(); Specification spec = SoftwareModuleSpecification.equalType(type); specList.add(spec); @@ -257,7 +257,7 @@ public class SoftwareManagement { /** * retrieves {@link SoftwareModule}s by their name AND version. - * + * * @param name * of the {@link SoftwareModule} * @param version @@ -273,7 +273,7 @@ public class SoftwareManagement { /** * Deletes the given {@link SoftwareModule} {@link Entity}. - * + * * @param bsm * is the {@link SoftwareModule} to be deleted */ @@ -291,26 +291,12 @@ public class SoftwareManagement { private Slice findSwModuleByCriteriaAPI(@NotNull final Pageable pageable, @NotEmpty final List> specList) { - - Specifications specs = Specifications.where(specList.get(0)); - if (specList.size() > 1) { - for (final Specification s : specList.subList(1, specList.size())) { - specs = specs.and(s); - } - } - - return criteriaNoCountDao.findAll(specs, pageable, SoftwareModule.class); + return criteriaNoCountDao.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable, + SoftwareModule.class); } private Long countSwModuleByCriteriaAPI(@NotEmpty final List> specList) { - Specifications specs = Specifications.where(specList.get(0)); - if (specList.size() > 1) { - for (final Specification s : specList.subList(1, specList.size())) { - specs = specs.and(s); - } - } - - return softwareModuleRepository.count(specs); + return softwareModuleRepository.count(SpecificationsBuilder.combineWithAnd(specList)); } private void deleteGridFsArtifacts(final SoftwareModule swModule) { @@ -321,7 +307,7 @@ public class SoftwareManagement { /** * Deletes {@link SoftwareModule}s which is any if the given ids. - * + * * @param ids * of the Software Moduels to be deleted */ @@ -366,20 +352,16 @@ public class SoftwareManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) public Slice findSoftwareModulesAll(@NotNull final Pageable pageable) { - final List> specList = new ArrayList>(); + final List> specList = new ArrayList<>(); Specification spec = SoftwareModuleSpecification.isDeletedFalse(); specList.add(spec); - spec = new Specification() { - @Override - public Predicate toPredicate(final Root root, final CriteriaQuery query, - final CriteriaBuilder cb) { - if (!query.getResultType().isAssignableFrom(Long.class)) { - root.fetch(SoftwareModule_.type); - } - return cb.conjunction(); + spec = (root, query, cb) -> { + if (!query.getResultType().isAssignableFrom(Long.class)) { + root.fetch(SoftwareModule_.type); } + return cb.conjunction(); }; specList.add(spec); @@ -396,7 +378,7 @@ public class SoftwareManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) public Long countSoftwareModulesAll() { - final List> specList = new ArrayList>(); + final List> specList = new ArrayList<>(); final Specification spec = SoftwareModuleSpecification.isDeletedFalse(); specList.add(spec); @@ -479,7 +461,7 @@ public class SoftwareManagement { public Slice findSoftwareModuleByFilters(@NotNull final Pageable pageable, final String searchText, final SoftwareModuleType type) { - final List> specList = new ArrayList>(); + final List> specList = new ArrayList<>(); Specification spec = SoftwareModuleSpecification.isDeletedFalse(); specList.add(spec); @@ -494,15 +476,11 @@ public class SoftwareManagement { specList.add(spec); } - spec = new Specification() { - @Override - public Predicate toPredicate(final Root root, final CriteriaQuery query, - final CriteriaBuilder cb) { - if (!query.getResultType().isAssignableFrom(Long.class)) { - root.fetch(SoftwareModule_.type); - } - return cb.conjunction(); + spec = (root, query, cb) -> { + if (!query.getResultType().isAssignableFrom(Long.class)) { + root.fetch(SoftwareModule_.type); } + return cb.conjunction(); }; specList.add(spec); @@ -592,7 +570,7 @@ public class SoftwareManagement { private List> buildSpecificationList(final String searchText, final SoftwareModuleType type) { - final List> specList = new ArrayList>(); + final List> specList = new ArrayList<>(); if (!Strings.isNullOrEmpty(searchText)) { specList.add(SoftwareModuleSpecification.likeNameOrVersion(searchText)); } @@ -631,7 +609,7 @@ public class SoftwareManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) public Long countSoftwareModuleByFilters(final String searchText, final SoftwareModuleType type) { - final List> specList = new ArrayList>(); + final List> specList = new ArrayList<>(); Specification spec = SoftwareModuleSpecification.isDeletedFalse(); specList.add(spec); @@ -788,7 +766,7 @@ public class SoftwareManagement { /** * 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 @@ -813,7 +791,7 @@ public class SoftwareManagement { /** * 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 @@ -835,7 +813,7 @@ public class SoftwareManagement { /** * 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 @@ -858,7 +836,7 @@ public class SoftwareManagement { /** * deletes a software module meta data entry. - * + * * @param id * the ID of the software module meta data to delete */ @@ -871,7 +849,7 @@ public class SoftwareManagement { /** * finds all meta data by the given software module id. - * + * * @param swId * the software module id to retrieve the meta data from * @param pageable @@ -887,7 +865,7 @@ public class SoftwareManagement { /** * finds all meta data by the given software module id. - * + * * @param softwareModuleId * the software module id to retrieve the meta data from * @param spec @@ -900,20 +878,19 @@ public class SoftwareManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId, @NotNull final Specification spec, @NotNull final Pageable pageable) { - return softwareModuleMetadataRepository.findAll(new Specification() { - @Override - public Predicate toPredicate(final Root root, final CriteriaQuery query, - final CriteriaBuilder cb) { - - return cb.and(cb.equal(root.get(SoftwareModuleMetadata_.softwareModule).get(SoftwareModule_.id), - softwareModuleId), spec.toPredicate(root, query, cb)); - } - }, 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 diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java index 11781559e..c55127d0f 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java @@ -16,6 +16,7 @@ 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; @@ -33,7 +34,7 @@ import com.google.common.base.Strings; /** * Business service facade for managing {@link TargetFilterQuery}s. - * + * * * */ @@ -47,7 +48,7 @@ public class TargetFilterQueryManagement { /** * creating new {@link TargetFilterQuery}. - * + * * @param customTargetFilter * @return the created {@link TargetFilterQuery} */ @@ -60,13 +61,12 @@ public class TargetFilterQueryManagement { if (targetFilterQueryRepository.findByName(customTargetFilter.getName()) != null) { throw new EntityAlreadyExistsException(customTargetFilter.getName()); } - final TargetFilterQuery filter = targetFilterQueryRepository.save(customTargetFilter); - return filter; + return targetFilterQueryRepository.save(customTargetFilter); } /** * Delete target filter query. - * + * * @param targetFilterQueryId * IDs of target filter query to be deleted */ @@ -78,9 +78,9 @@ public class TargetFilterQueryManagement { } /** - * + * * Retrieves all target filter query{@link TargetFilterQuery}. - * + * * @param pageable * pagination parameter * @return the found {@link TargetFilterQuery}s @@ -92,8 +92,8 @@ public class TargetFilterQueryManagement { /** * Retrieves all target filter query which {@link TargetFilterQuery}. - * - * + * + * * @param pageable * pagination parameter * @param name @@ -102,7 +102,7 @@ public class TargetFilterQueryManagement { */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) public Page findTargetFilterQueryByFilters(@NotNull final Pageable pageable, final String name) { - final List> specList = new ArrayList>(); + final List> specList = new ArrayList<>(); if (!Strings.isNullOrEmpty(name)) { specList.add(TargetFilterQuerySpecification.likeName(name)); } @@ -110,7 +110,7 @@ public class TargetFilterQueryManagement { } /** - * + * * @param pageable * pagination parameter * @param specList @@ -119,29 +119,21 @@ public class TargetFilterQueryManagement { */ private Page findTargetFilterQueryByCriteriaAPI(@NotNull final Pageable pageable, final List> specList) { - Specifications specs = null; - if (!specList.isEmpty()) { - specs = Specifications.where(specList.get(0)); - } - if (specList.size() > 1) { - for (final Specification s : specList.subList(1, specList.size())) { - specs = specs.and(s); - } - } - if (specs == null) { + if (specList == null || specList.isEmpty()) { return targetFilterQueryRepository.findAll(pageable); - } else { - return targetFilterQueryRepository.findAll(specs, 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) { @@ -150,11 +142,11 @@ public class TargetFilterQueryManagement { /** * 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) { @@ -163,7 +155,7 @@ public class TargetFilterQueryManagement { /** * updates the {@link TargetFilterQuery}. - * + * * @param targetFilterQuery * to be updated * @return the updated {@link 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 index 75e8c67f3..e790d0a5e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java @@ -47,6 +47,7 @@ import org.eclipse.hawkbit.repository.model.TargetTagAssigmentResult; 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; @@ -59,7 +60,6 @@ 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.domain.Specifications; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; @@ -508,39 +508,18 @@ public class TargetManagement { * @return the page with the found {@link Target} */ private Slice findByCriteriaAPI(final Pageable pageable, final List> specList) { - final Specifications specs = creatingTargetSpecifications(specList); - - if (specs == null) { + if (specList == null || specList.isEmpty()) { return criteriaNoCountDao.findAll(pageable, Target.class); - } else { - return criteriaNoCountDao.findAll(specs, pageable, Target.class); } - + return criteriaNoCountDao.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable, Target.class); } private Long countByCriteriaAPI(final List> specList) { - final Specifications specs = creatingTargetSpecifications(specList); - - if (specs == null) { + if (specList == null || specList.isEmpty()) { return targetRepository.count(); - } else { - return targetRepository.count(specs); } - } - - private static Specifications creatingTargetSpecifications(final List> specList) { - Specifications specs = null; - if (!specList.isEmpty()) { - specs = Specifications.where(specList.get(0)); - } - if (specList.size() > 1) { - specList.remove(0); - for (final Specification s : specList) { - specs = specs.and(s); - } - } - return specs; + return targetRepository.count(SpecificationsBuilder.combineWithAnd(specList)); } /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Rollout.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Rollout.java index 3b678ec48..83e541ed5 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Rollout.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Rollout.java @@ -77,7 +77,7 @@ public class Rollout extends NamedEntity { private int rolloutGroupsCreated = 0; @Transient - private TotalTargetCountStatus totalTargetCountStatus; + private transient TotalTargetCountStatus totalTargetCountStatus; /** * @return the distributionSet @@ -234,7 +234,7 @@ public class Rollout extends NamedEntity { */ public TotalTargetCountStatus getTotalTargetCountStatus() { if (totalTargetCountStatus == null) { - this.totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); + totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); } return totalTargetCountStatus; } @@ -255,11 +255,11 @@ public class Rollout extends NamedEntity { } /** - * + * * @author Michael Hirsch * */ - public static enum RolloutStatus { + public enum RolloutStatus { /** * Rollouts is beeing created. 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 index ad7efdf1f..dcb95b254 100644 --- 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 @@ -27,7 +27,7 @@ import javax.persistence.UniqueConstraint; /** * JPA entity definition of persisting a group of an rollout. - * + * * @author Michael Hirsch * */ @@ -116,7 +116,7 @@ public class RolloutGroup extends NamedEntity { } public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) { - this.successCondition = finishCondition; + successCondition = finishCondition; } public String getSuccessConditionExp() { @@ -124,7 +124,7 @@ public class RolloutGroup extends NamedEntity { } public void setSuccessConditionExp(final String finishExp) { - this.successConditionExp = finishExp; + successConditionExp = finishExp; } public RolloutGroupErrorCondition getErrorCondition() { @@ -140,7 +140,7 @@ public class RolloutGroup extends NamedEntity { } public void setErrorConditionExp(final String errorExp) { - this.errorConditionExp = errorExp; + errorConditionExp = errorExp; } public RolloutGroupErrorAction getErrorAction() { @@ -188,7 +188,7 @@ public class RolloutGroup extends NamedEntity { */ public TotalTargetCountStatus getTotalTargetCountStatus() { if (totalTargetCountStatus == null) { - this.totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); + totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); } return totalTargetCountStatus; } @@ -210,7 +210,7 @@ public class RolloutGroup extends NamedEntity { } /** - * + * * @author Michael Hirsch * */ @@ -343,7 +343,7 @@ public class RolloutGroup extends NamedEntity { } public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) { - this.successCondition = finishCondition; + successCondition = finishCondition; } public String getSuccessConditionExp() { @@ -351,7 +351,7 @@ public class RolloutGroup extends NamedEntity { } public void setSuccessConditionExp(final String finishConditionExp) { - this.successConditionExp = finishConditionExp; + successConditionExp = finishConditionExp; } public RolloutGroupSuccessAction getSuccessAction() { @@ -416,7 +416,7 @@ public class RolloutGroup extends NamedEntity { /** * Sets the finish condition and expression on the builder. - * + * * @param condition * the finish condition * @param expression @@ -432,7 +432,7 @@ public class RolloutGroup extends NamedEntity { /** * Sets the success action and expression on the builder. - * + * * @param action * the success action * @param expression @@ -448,7 +448,7 @@ public class RolloutGroup extends NamedEntity { /** * Sets the error condition and expression on the builder. - * + * * @param condition * the error condition * @param expression @@ -464,7 +464,7 @@ public class RolloutGroup extends NamedEntity { /** * Sets the error action and expression on the builder. - * + * * @param action * the error action * @param expression diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutTargetGroup.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutTargetGroup.java index a185f481f..f1d4fe718 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutTargetGroup.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/RolloutTargetGroup.java @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.repository.model; +import java.io.Serializable; import java.util.List; import javax.persistence.CascadeType; @@ -30,16 +31,18 @@ import javax.persistence.Table; @IdClass(RolloutTargetGroupId.class) @Entity @Table(name = "sp_rollouttargetgroup") -public class RolloutTargetGroup { +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")) + @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")) + @JoinColumn(name = "target_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollouttargetgroup_target") ) private Target target; @OneToMany(targetEntity = Action.class, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }) diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Target.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Target.java index 6de84ccaa..08e4fcecb 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Target.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Target.java @@ -32,6 +32,8 @@ import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.UniqueConstraint; +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; @@ -74,6 +76,8 @@ public class Target extends NamedEntity implements Persistable { private static final long serialVersionUID = 1L; @Column(name = "controller_id", length = 64) + @Size(min = 1) + @NotNull private String controllerId; @Transient diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountStatus.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountStatus.java index f403ecc3d..13c41baf3 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountStatus.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TotalTargetCountStatus.java @@ -9,12 +9,12 @@ package org.eclipse.hawkbit.repository.model; import java.util.Collections; -import java.util.HashMap; +import java.util.EnumMap; import java.util.List; import java.util.Map; /** - * + * * Store all states with the target count of a rollout or rolloutgroup. * */ @@ -27,12 +27,12 @@ public class TotalTargetCountStatus { SCHEDULED, RUNNING, ERROR, FINISHED, CANCELLED, NOTSTARTED } - private final Map statusTotalCountMap = new HashMap<>(); + private final Map statusTotalCountMap = new EnumMap<>(Status.class); private final Long totalTargetCount; /** * Create a new states map with the target count for each state. - * + * * @param targetCountActionStatus * the action state map * @param totalTargets @@ -46,7 +46,7 @@ public class TotalTargetCountStatus { /** * Create a new states map with the target count for each state. - * + * * @param totalTargetCount * the total target count */ @@ -56,7 +56,7 @@ public class TotalTargetCountStatus { /** * The current state mape which the total target count - * + * * @return the statusTotalCountMap the state map */ public Map getStatusTotalCountMap() { @@ -65,7 +65,7 @@ public class TotalTargetCountStatus { /** * Gets the total target count from a state. - * + * * @param status * the state key * @return the current target count cannot be @@ -77,7 +77,7 @@ public class TotalTargetCountStatus { /** * Populate all target status to a the given map - * + * * @param statusTotalCountMap * the map * @param rolloutStatusCountItems diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLUtility.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLUtility.java index 69ee58429..03f213fef 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLUtility.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLUtility.java @@ -18,6 +18,7 @@ import java.util.stream.Collectors; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Expression; import javax.persistence.criteria.MapJoin; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; @@ -101,7 +102,7 @@ public final class RSQLUtility { */ public static & FieldNameProvider, T> Specification parse(final String rsql, final Class fieldNameProvider) { - return new RSQLSpecification<>(rsql, fieldNameProvider); + return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider); } /** @@ -460,16 +461,46 @@ public final class RSQLUtility { singleList.add(cb.lessThanOrEqualTo(pathOfString(fieldPath), value)); break; case "=in=": - singleList.add(fieldPath.in(transformedValues)); + singleList.add(getInPredicate(transformedValues, fieldPath)); break; case "=out=": - singleList.add(cb.not(fieldPath.in(transformedValues))); + singleList.add(getOutPredicate(transformedValues, fieldPath)); break; default: LOGGER.info("operator symbol {} is either not supported or not implemented"); } } + private Predicate getInPredicate(final List transformedValues, final Path fieldPath) { + final List inParams = new ArrayList<>(); + for (final Object param : transformedValues) { + if (param instanceof String) { + inParams.add(((String) param).toUpperCase()); + } + } + if (!inParams.isEmpty()) { + return cb.upper(pathOfString(fieldPath)).in(inParams); + } else { + return fieldPath.in(transformedValues); + + } + } + + private Predicate getOutPredicate(final List transformedValues, final Path fieldPath) { + final List outParams = new ArrayList<>(); + for (final Object param : transformedValues) { + if (param instanceof String) { + outParams.add(((String) param).toUpperCase()); + } + } + if (!outParams.isEmpty()) { + return cb.not(cb.upper(pathOfString(fieldPath)).in(outParams)); + } else { + return cb.not(fieldPath.in(transformedValues)); + + } + } + private Path getMapValueFieldPath(final A enumField, final Path fieldPath) { if (!enumField.isMap() || enumField.getValueFieldName() == null) { return fieldPath; @@ -477,6 +508,7 @@ public final class RSQLUtility { return fieldPath.get(enumField.getValueFieldName()); } + @SuppressWarnings("unchecked") private Predicate mapToMapPredicate(final ComparisonNode node, final Path fieldPath, final A enumField) { if (!enumField.isMap()) { @@ -485,10 +517,12 @@ public final class RSQLUtility { final String[] graph = node.getSelector().split("\\" + FieldNameProvider.SUB_ATTRIBUTE_SEPERATOR); final String keyValue = graph[graph.length - 1]; if (fieldPath instanceof MapJoin) { - return cb.equal(((MapJoin) fieldPath).key(), keyValue); + // Currently we support only string key .So below cast is safe. + return cb.equal(cb.upper((Expression) (((MapJoin) fieldPath).key())), + keyValue.toUpperCase()); } - return cb.equal(fieldPath.get(enumField.getKeyFieldName()), keyValue); + return cb.equal(cb.upper(fieldPath.get(enumField.getKeyFieldName())), keyValue.toUpperCase()); } private Predicate getEqualToPredicate(final Object transformedValue, final Path fieldPath) { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/SpecificationsBuilder.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/SpecificationsBuilder.java new file mode 100644 index 000000000..83a4c6f8b --- /dev/null +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/specifications/SpecificationsBuilder.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.specifications; + +import java.util.List; + +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.domain.Specifications; + +/** + * Helper class to easily combine {@link Specification} instances. + * + */ +public final class SpecificationsBuilder { + + private SpecificationsBuilder() { + + } + + /** + * Combine all given specification with and. The first specification is the + * where clause. + * + * @param specList + * all specification wich will combine + * @return if the given specification list is empty + */ + public static Specifications combineWithAnd(final List> specList) { + if (specList.isEmpty()) { + return null; + } + Specifications specs = Specifications.where(specList.get(0)); + specList.remove(0); + for (final Specification specification : specList) { + specs = specs.and(specification); + } + return specs; + } + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/RolloutGroupConditionEvaluator.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/RolloutGroupConditionEvaluator.java index 73580fd19..62c9050b1 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/RolloutGroupConditionEvaluator.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/RolloutGroupConditionEvaluator.java @@ -16,7 +16,19 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup; */ public interface RolloutGroupConditionEvaluator { - boolean verifyExpression(final String expression); + default boolean verifyExpression(final String expression) { + // percentage value between 0 and 100 + try { + final Integer value = Integer.valueOf(expression); + if (value >= 0 || value <= 100) { + return true; + } + return true; + } catch (final NumberFormatException e) { + + return false; + } + } boolean eval(Rollout rollout, RolloutGroup rolloutGroup, final String expression); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupErrorCondition.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupErrorCondition.java index 2c2bc361f..6e63efa8e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupErrorCondition.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupErrorCondition.java @@ -18,31 +18,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** - * + * */ @Component("thresholdRolloutGroupErrorCondition") public class ThresholdRolloutGroupErrorCondition implements RolloutGroupConditionEvaluator { - private static Logger logger = LoggerFactory.getLogger(ThresholdRolloutGroupErrorCondition.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ThresholdRolloutGroupErrorCondition.class); @Autowired private ActionRepository actionRepository; - @Override - public boolean verifyExpression(final String expression) { - // percentage value between 0 and 100 - try { - final Integer value = Integer.valueOf(expression); - if (value >= 0 || value <= 100) { - return true; - } - return true; - } catch (final RuntimeException e) { - - } - return false; - } - @Override public boolean eval(final Rollout rollout, final RolloutGroup rolloutGroup, final String expression) { final Long totalGroup = actionRepository.countByRolloutAndRolloutGroup(rollout, rolloutGroup); @@ -60,7 +45,7 @@ public class ThresholdRolloutGroupErrorCondition implements RolloutGroupConditio // calculate threshold return ((float) error / (float) totalGroup) > ((float) threshold / 100F); } catch (final NumberFormatException e) { - logger.error("Cannot evaluate condition expression " + expression, e); + LOGGER.error("Cannot evaluate condition expression " + expression, e); return false; } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupSuccessCondition.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupSuccessCondition.java index 81b5c7286..fcf9762c6 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupSuccessCondition.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/rollout/condition/ThresholdRolloutGroupSuccessCondition.java @@ -12,47 +12,41 @@ import org.eclipse.hawkbit.repository.ActionRepository; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** - * + * */ @Component("thresholdRolloutGroupSuccessCondition") public class ThresholdRolloutGroupSuccessCondition implements RolloutGroupConditionEvaluator { + private static final Logger LOGGER = LoggerFactory.getLogger(ThresholdRolloutGroupSuccessCondition.class); @Autowired private ActionRepository actionRepository; - @Override - public boolean verifyExpression(final String expression) { - // percentage value between 0 and 100 - try { - final Integer value = Integer.valueOf(expression); - if (value >= 0 || value <= 100) { - return true; - } - return true; - } catch (final RuntimeException e) { - - } - return false; - } - @Override public boolean eval(final Rollout rollout, final RolloutGroup rolloutGroup, final String expression) { final Long totalGroup = rolloutGroup.getTotalTargets(); - final Long finished = actionRepository.countByRolloutIdAndRolloutGroupIdAndStatus(rollout.getId(), + final Long finished = this.actionRepository.countByRolloutIdAndRolloutGroupIdAndStatus(rollout.getId(), rolloutGroup.getId(), Action.Status.FINISHED); - final Integer threshold = Integer.valueOf(expression); + try { + final Integer threshold = Integer.valueOf(expression); - if (totalGroup == 0) { - // in case e.g. targets has been deleted we don't have any actions - // left for this group, so the group is finished - return true; + if (totalGroup == 0) { + // in case e.g. targets has been deleted we don't have any + // actions + // left for this group, so the group is finished + return true; + } + // calculate threshold + return ((float) finished / (float) totalGroup) >= ((float) threshold / 100F); + } catch (final NumberFormatException e) { + LOGGER.error("Cannot evaluate condition expression " + expression, e); + return false; } - // calculate threshold - return ((float) finished / (float) totalGroup) >= ((float) threshold / 100F); } } 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 index 8289b8173..41a7c7848 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ControllerManagementTest.java +++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ControllerManagementTest.java @@ -9,10 +9,13 @@ 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; @@ -71,6 +74,24 @@ public class ControllerManagementTest extends AbstractIntegrationTest { .getNumberOfElements()).isEqualTo(3); } + @Test + @Description("Register a controller which 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); + + try { + controllerManagament.findOrRegisterTargetIfItDoesNotexist("", null); + fail("target with empty controller id should not be registred"); + } catch (final ConstraintViolationException e) { + // ok + } + } + @Test @Description("Controller trys to finish an update process after it has been finished by an error action status.") public void tryToFinishUpdateProcessMoreThenOnce() { diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ReportManagementTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ReportManagementTest.java index 5c9c86aa7..bb5450083 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ReportManagementTest.java +++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/ReportManagementTest.java @@ -99,7 +99,7 @@ public class ReportManagementTest extends AbstractIntegrationTest { assertThat(targetsCreatedOverPeriod.getData()).hasSize(maxMonthBackAmountReportTargets + 1); for (final DataReportSeriesItem reportItem : targetsCreatedOverPeriod.getData()) { // only one target is created for each month - assertThat(reportItem.getData().intValue()).isEqualTo(1); + assertThat(reportItem.getData().intValue()).as("Target for each month").isEqualTo(1); } // check cache evict @@ -109,7 +109,7 @@ public class ReportManagementTest extends AbstractIntegrationTest { } targetsCreatedOverPeriod = reportManagement.targetsCreatedOverPeriod(DateTypes.perMonth(), from, to); for (final DataReportSeriesItem reportItem : targetsCreatedOverPeriod.getData()) { - assertThat(reportItem.getData().intValue()).isEqualTo(2); + assertThat(reportItem.getData().intValue()).as("Target for each month").isEqualTo(2); } } @@ -221,21 +221,26 @@ public class ReportManagementTest extends AbstractIntegrationTest { .getData()[0]; if (dataReportSeriesItem.getType().equals("ds1")) { // total count of three because ds1 has two different versions - assertThat(dataReportSeriesItem.getData()).isEqualTo(3L); + assertThat(dataReportSeriesItem.getData()).as("Version/Item type of DistributionSet 1 in statistics") + .isEqualTo(3L); final DataReportSeriesItem[] outerData = innerOuterDataReportSeries.getOuterSeries().getData(); assertThat(Arrays.stream(outerData).map(DataReportSeriesItem::getType).collect(Collectors.toList())) .contains("0.0.0", "0.0.1"); } else if (dataReportSeriesItem.getType().equals("ds2")) { - assertThat(dataReportSeriesItem.getData()).isEqualTo(1L); + assertThat(dataReportSeriesItem.getData()).as("Version/Item type of DistributionSet 2 in statistics") + .isEqualTo(1L); final DataReportSeriesItem[] outerData = innerOuterDataReportSeries.getOuterSeries().getData(); assertThat(outerData).hasSize(1); - assertThat(outerData[0].getType()).isEqualTo("0.0.2"); - + assertThat(outerData[0].getType()).as("Version/Item type of DistributionSet 2 in statistics") + .isEqualTo("0.0.2"); } else if (dataReportSeriesItem.getType().equals("ds3")) { - assertThat(dataReportSeriesItem.getData()).isEqualTo(0L); + + assertThat(dataReportSeriesItem.getData()).as("Version/Item type of DistributionSet 3 in statistics") + .isEqualTo(0L); final DataReportSeriesItem[] outerData = innerOuterDataReportSeries.getOuterSeries().getData(); assertThat(outerData).hasSize(1); - assertThat(outerData[0].getType()).isEqualTo("0.0.3"); + assertThat(outerData[0].getType()).as("Version/Item type of DistributionSet 3 in statistics") + .isEqualTo("0.0.3"); } else { fail("no assertion count for distribution set " + dataReportSeriesItem.getType()); } @@ -251,8 +256,7 @@ public class ReportManagementTest extends AbstractIntegrationTest { final DataReportSeriesItem dataReportSeriesItem = innerOuterDataReportSeries.getInnerSeries() .getData()[0]; if (dataReportSeriesItem.getType().equals("ds1")) { - assertThat(dataReportSeriesItem.getData()).isEqualTo(4L); - + assertThat(dataReportSeriesItem.getData()).as("Data report item number").isEqualTo(4L); } } } @@ -278,19 +282,23 @@ public class ReportManagementTest extends AbstractIntegrationTest { switch (reportItem.getType()) { case ERROR: - assertThat(reportItem.getData()).isEqualTo(knownErrorCount); + assertThat(reportItem.getData()).as("ERROR count for targets in statistics").isEqualTo(knownErrorCount); break; case IN_SYNC: - assertThat(reportItem.getData()).isEqualTo(knownSyncCount); + assertThat(reportItem.getData()).as("IN_SYNC count for targets in statistics") + .isEqualTo(knownSyncCount); break; case PENDING: - assertThat(reportItem.getData()).isEqualTo(knownPendingCount); + assertThat(reportItem.getData()).as("PENDING count for targets in statistics") + .isEqualTo(knownPendingCount); break; case REGISTERED: - assertThat(reportItem.getData()).isEqualTo(knownRegCount); + assertThat(reportItem.getData()).as("REGISTERED count for targets in statistics") + .isEqualTo(knownRegCount); break; case UNKNOWN: - assertThat(reportItem.getData()).isEqualTo(knownUnknownCount); + assertThat(reportItem.getData()).as("UNKNOWN count for targets in statistics") + .isEqualTo(knownUnknownCount); break; default: fail("missing case for unknown target update status " + reportItem.getType()); @@ -309,19 +317,24 @@ public class ReportManagementTest extends AbstractIntegrationTest { switch (reportItem.getType()) { case ERROR: - assertThat(reportItem.getData()).isEqualTo(knownErrorCount * 2); + assertThat(reportItem.getData()).as("ERROR count for targets in statistics") + .isEqualTo(knownErrorCount * 2); break; case IN_SYNC: - assertThat(reportItem.getData()).isEqualTo(knownSyncCount * 2); + assertThat(reportItem.getData()).as("IN_SYNC count for targets in statistics") + .isEqualTo(knownSyncCount * 2); break; case PENDING: - assertThat(reportItem.getData()).isEqualTo(knownPendingCount * 2); + assertThat(reportItem.getData()).as("PENDING count for targets in statistics") + .isEqualTo(knownPendingCount * 2); break; case REGISTERED: - assertThat(reportItem.getData()).isEqualTo(knownRegCount * 2); + assertThat(reportItem.getData()).as("REGISTERED count for targets in statistics") + .isEqualTo(knownRegCount * 2); break; case UNKNOWN: - assertThat(reportItem.getData()).isEqualTo(knownUnknownCount * 2); + assertThat(reportItem.getData()).as("UNKNOWN count for targets in statistics") + .isEqualTo(knownUnknownCount * 2); break; default: fail("missing case for unknown target update status " + reportItem.getType()); @@ -373,22 +386,30 @@ public class ReportManagementTest extends AbstractIntegrationTest { final DataReportSeriesItem dataReportSeriesItem = innerOuterDataReportSeries.getInnerSeries() .getData()[0]; if (dataReportSeriesItem.getType().equals("ds1")) { + // total count of three because ds1 has two different versions - assertThat(dataReportSeriesItem.getData()).isEqualTo(3L); + assertThat(dataReportSeriesItem.getData()).as("Total count of DistributionSet 1 in statistics") + .isEqualTo(3L); + final DataReportSeriesItem[] outerData = innerOuterDataReportSeries.getOuterSeries().getData(); assertThat(Arrays.stream(outerData).map(DataReportSeriesItem::getType).collect(Collectors.toList())) .contains("0.0.0", "0.0.1"); + } else if (dataReportSeriesItem.getType().equals("ds2")) { - assertThat(dataReportSeriesItem.getData()).isEqualTo(1L); + assertThat(dataReportSeriesItem.getData()).as("Total count of DistributionSet 2 in statistics") + .isEqualTo(1L); final DataReportSeriesItem[] outerData = innerOuterDataReportSeries.getOuterSeries().getData(); assertThat(outerData).hasSize(1); - assertThat(outerData[0].getType()).isEqualTo("0.0.2"); + assertThat(outerData[0].getType()).as("Version/Item type of DistributionSet 2 in statistics") + .isEqualTo("0.0.2"); } else if (dataReportSeriesItem.getType().equals("ds3")) { - assertThat(dataReportSeriesItem.getData()).isEqualTo(0L); + assertThat(dataReportSeriesItem.getData()).as("Total count of DistributionSet 3 in statistics") + .isEqualTo(0L); final DataReportSeriesItem[] outerData = innerOuterDataReportSeries.getOuterSeries().getData(); assertThat(outerData).hasSize(1); - assertThat(outerData[0].getType()).isEqualTo("0.0.3"); + assertThat(outerData[0].getType()).as("Version/Item type of DistributionSet 3 in statistics") + .isEqualTo("0.0.3"); } else { fail("no assertion count for distribution set " + dataReportSeriesItem.getType()); } @@ -402,7 +423,8 @@ public class ReportManagementTest extends AbstractIntegrationTest { final DataReportSeriesItem dataReportSeriesItem = innerOuterDataReportSeries.getInnerSeries() .getData()[0]; if (dataReportSeriesItem.getType().equals("ds1")) { - assertThat(dataReportSeriesItem.getData()).isEqualTo(4L); + assertThat(dataReportSeriesItem.getData()).as("Total count of DistributionSet 1 in statistics") + .isEqualTo(4L); } } } @@ -435,29 +457,24 @@ public class ReportManagementTest extends AbstractIntegrationTest { DataReportSeries targetsNotLastPoll = reportManagement.targetsLastPoll(); DataReportSeriesItem[] data = targetsNotLastPoll.getData(); - // for( final DataReportSeriesItem dataReportSeriesItem : - // data ) { - // System.out.println( dataReportSeriesItem.getData() ); - // } - // --- Verfiy --- // verify hour - assertThat(data[0].getType()).isEqualTo(SeriesTime.HOUR); - assertThat(data[0].getData()).isEqualTo((long) knownTargetsPollLastHour); + assertThat(data[0].getType()).as("Series time").isEqualTo(SeriesTime.HOUR); + assertThat(data[0].getData()).as("Targets poll last hour").isEqualTo((long) knownTargetsPollLastHour); // verify day - assertThat(data[1].getType()).isEqualTo(SeriesTime.DAY); - assertThat(data[1].getData()).isEqualTo((long) knownTargetsPollLastDay); + assertThat(data[1].getType()).as("Series time").isEqualTo(SeriesTime.DAY); + assertThat(data[1].getData()).as("Targets poll last day").isEqualTo((long) knownTargetsPollLastDay); // verify week - assertThat(data[2].getType()).isEqualTo(SeriesTime.WEEK); - assertThat(data[2].getData()).isEqualTo((long) knownTargetsPollLastWeek); + assertThat(data[2].getType()).as("Series time").isEqualTo(SeriesTime.WEEK); + assertThat(data[2].getData()).as("Targets poll last week").isEqualTo((long) knownTargetsPollLastWeek); // test cache evict createTargets("hourPoll2", knownTargetsPollLastHour, now.minusMinutes(59)); targetsNotLastPoll = reportManagement.targetsLastPoll(); data = targetsNotLastPoll.getData(); - assertThat(data[0].getType()).isEqualTo(SeriesTime.HOUR); - assertThat(data[0].getData()).isEqualTo((long) knownTargetsPollLastHour * 2); + assertThat(data[0].getType()).as("Series time").isEqualTo(SeriesTime.HOUR); + assertThat(data[0].getData()).as("Targets poll last hour").isEqualTo((long) knownTargetsPollLastHour * 2); } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementTest.java index a7b8e673f..3a70441ca 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementTest.java +++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementTest.java @@ -10,7 +10,6 @@ package org.eclipse.hawkbit.repository; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -26,6 +25,7 @@ import java.util.Set; import java.util.stream.Collectors; import javax.persistence.Query; +import javax.validation.ConstraintViolationException; import org.eclipse.hawkbit.AbstractIntegrationTest; import org.eclipse.hawkbit.TestDataUtil; @@ -65,6 +65,24 @@ public class TargetManagementTest extends AbstractIntegrationTest { } } + @Test + @Description("Verify that a target with empty controller id cannot be created") + public void createTargetWithNoControllerId() { + try { + targetManagement.createTarget(new Target("")); + fail("target with empty controller id should not be created"); + } catch (final ConstraintViolationException e) { + // ok + } + + try { + targetManagement.createTarget(new Target(null)); + fail("target with empty controller id should not be created"); + } catch (final ConstraintViolationException e) { + // ok + } + } + @Test @Description("Ensures that targets can assigned and unassigned to a target tag. Not exists target will be ignored for the assignment.") public void assignAndUnassignTargetsToTag() { @@ -226,10 +244,10 @@ public class TargetManagementTest extends AbstractIntegrationTest { } } if (strict) { - fail(); + fail("Target does not contain all tags"); } } - fail(); + fail("Target does not contain any tags or the expected tag was not found"); } } @@ -240,7 +258,7 @@ public class TargetManagementTest extends AbstractIntegrationTest { for (final Tag tag : tags) { for (final Tag tt : t.getTags()) { if (tag.getName().equals(tt.getName())) { - fail(); + fail("Target should have no tags"); } } } @@ -256,30 +274,33 @@ public class TargetManagementTest extends AbstractIntegrationTest { final Target target = TestDataUtil.buildTargetFixture(myCtrlID, "the description!"); Target savedTarget = targetManagement.createTarget(target); - assertNotNull(savedTarget); + assertNotNull("The target should not be null", savedTarget); final Long createdAt = savedTarget.getCreatedAt(); Long modifiedAt = savedTarget.getLastModifiedAt(); - assertEquals(createdAt, modifiedAt); - assertNotNull(savedTarget.getCreatedAt()); - assertNotNull(savedTarget.getLastModifiedAt()); - assertEquals(target, savedTarget); + + assertThat(createdAt).as("CreatedAt compared with modifiedAt").isEqualTo(modifiedAt); + assertNotNull("The createdAt attribut of the target should no be null", savedTarget.getCreatedAt()); + assertNotNull("The lastModifiedAt attribut of the target should no be null", savedTarget.getLastModifiedAt()); + assertThat(target).as("Target compared with saved target").isEqualTo(savedTarget); savedTarget.setDescription("changed description"); Thread.sleep(1); savedTarget = targetManagement.updateTarget(savedTarget); - - assertNotNull(savedTarget.getLastModifiedAt()); - assertNotEquals(createdAt, savedTarget.getLastModifiedAt()); - assertNotEquals(modifiedAt, savedTarget.getLastModifiedAt()); + assertNotNull("The lastModifiedAt attribute of the target should not be null", savedTarget.getLastModifiedAt()); + assertThat(createdAt).as("CreatedAt compared with saved modifiedAt") + .isNotEqualTo(savedTarget.getLastModifiedAt()); + assertThat(modifiedAt).as("ModifiedAt compared with saved modifiedAt") + .isNotEqualTo(savedTarget.getLastModifiedAt()); modifiedAt = savedTarget.getLastModifiedAt(); final Target foundTarget = targetManagement.findTargetByControllerID(savedTarget.getControllerId()); - - assertNotNull(foundTarget); - assertEquals(myCtrlID, foundTarget.getControllerId()); - assertEquals(savedTarget, foundTarget); - assertEquals(createdAt, foundTarget.getCreatedAt()); - assertEquals(modifiedAt, foundTarget.getLastModifiedAt()); + assertNotNull("The target should not be null", foundTarget); + assertThat(myCtrlID).as("ControllerId compared with saved controllerId") + .isEqualTo(foundTarget.getControllerId()); + assertThat(savedTarget).as("Target compared with saved target").isEqualTo(foundTarget); + assertThat(createdAt).as("CreatedAt compared with saved createdAt").isEqualTo(foundTarget.getCreatedAt()); + assertThat(modifiedAt).as("LastModifiedAt compared with saved lastModifiedAt") + .isEqualTo(foundTarget.getLastModifiedAt()); } @Test @@ -296,8 +317,11 @@ public class TargetManagementTest extends AbstractIntegrationTest { final Target savedExtra = targetManagement.createTarget(extra); Iterable allFound = targetRepository.findAll(); - assertEquals(firstList.size(), firstSaved.spliterator().getExactSizeIfKnown()); - assertEquals(firstList.size() + 1, allFound.spliterator().getExactSizeIfKnown()); + + assertThat(Long.valueOf(firstList.size())).as("List size of targets") + .isEqualTo(firstSaved.spliterator().getExactSizeIfKnown()); + assertThat(Long.valueOf(firstList.size() + 1)).as("LastModifiedAt compared with saved lastModifiedAt") + .isEqualTo(allFound.spliterator().getExactSizeIfKnown()); // change the objects and save to again to trigger a change on // lastModifiedAt @@ -308,18 +332,23 @@ public class TargetManagementTest extends AbstractIntegrationTest { _founds: for (final Target foundTarget : allFound) { for (final Target changedTarget : firstSaved) { if (changedTarget.getControllerId().equals(foundTarget.getControllerId())) { - assertEquals(changedTarget.getDescription(), foundTarget.getDescription()); - assertTrue(changedTarget.getName().startsWith(foundTarget.getName())); - assertTrue(changedTarget.getName().endsWith("changed")); - assertEquals(changedTarget.getCreatedAt(), foundTarget.getCreatedAt()); - assertThat(changedTarget.getLastModifiedAt()).isNotEqualTo(changedTarget.getCreatedAt()); - + assertThat(changedTarget.getDescription()) + .as("Description of changed target compared with description saved target") + .isEqualTo(foundTarget.getDescription()); + assertThat(changedTarget.getName()).as("Name of changed target starts with name of saved target") + .startsWith(foundTarget.getName()); + assertThat(changedTarget.getName()).as("Name of changed target ends with 'changed'") + .endsWith("changed"); + assertThat(changedTarget.getCreatedAt()).as("CreatedAt compared with saved createdAt") + .isEqualTo(foundTarget.getCreatedAt()); + assertThat(changedTarget.getLastModifiedAt()).as("LastModifiedAt compared with saved createdAt") + .isNotEqualTo(changedTarget.getCreatedAt()); continue _founds; } } if (!foundTarget.getControllerId().equals(savedExtra.getControllerId())) { - fail(); + fail("The controllerId of the found target is not equal to the controllerId of the saved target"); } } @@ -341,8 +370,8 @@ public class TargetManagementTest extends AbstractIntegrationTest { targetManagement.deleteTargets(deletedTargetIDs); allFound = targetManagement.findTargetsAll(new PageRequest(0, 200)).getContent(); - assertEquals(firstSaved.spliterator().getExactSizeIfKnown() - nr2Del, - allFound.spliterator().getExactSizeIfKnown()); + assertThat(firstSaved.spliterator().getExactSizeIfKnown() - nr2Del).as("Size of splited list") + .isEqualTo(allFound.spliterator().getExactSizeIfKnown()); // verify that all undeleted are still found assertThat(allFound).doesNotContain(deletedTargets); @@ -376,15 +405,26 @@ public class TargetManagementTest extends AbstractIntegrationTest { } final Query qry = entityManager.createNativeQuery("select * from sp_target_attributes ta"); final List result = qry.getResultList(); - assertEquals(attribs.size() * ts.spliterator().getExactSizeIfKnown(), result.size()); + + assertThat(attribs.size() * ts.spliterator().getExactSizeIfKnown()).as("Amount of all target attributes") + .isEqualTo(result.size()); for (final Target myT : ts) { final Target t = targetManagement.findTargetByControllerIDWithDetails(myT.getControllerId()); - assertEquals(attribs.size(), t.getTargetInfo().getControllerAttributes().size()); + assertThat(attribs.size()).as("Amount of target attributes per target") + .isEqualTo(t.getTargetInfo().getControllerAttributes().size()); + for (final Entry ca : t.getTargetInfo().getControllerAttributes().entrySet()) { - assertTrue(attribs.containsKey(ca.getKey())); + assertTrue("Attributes list does not contain target attribute key", attribs.containsKey(ca.getKey())); // has the same value: see string concatenation above - assertEquals(String.format("%s-%s", attribs.get(ca.getKey()), t.getControllerId()), ca.getValue()); + // assertThat(String.format("%s-%s", + // attribs.get(ca.getKey()))).as("Value of string + // concatenation") + // .isEqualTo(ca.getValue()); + + assertEquals("The value of the string concatenation is not equal to the value of the target attributes", + String.format("%s-%s", attribs.get(ca.getKey()), t.getControllerId()), ca.getValue()); + } } @@ -656,9 +696,8 @@ public class TargetManagementTest extends AbstractIntegrationTest { final List targetsListWithNoTag = targetManagement .findTargetByFilters(new PageRequest(0, 500), null, null, null, Boolean.TRUE, tagNames).getContent(); - // Total targets - assertEquals(50, targetManagement.findAllTargetIds().size()); - // Targets with no tag - assertEquals(25, targetsListWithNoTag.size()); + assertThat(50).as("Total targets").isEqualTo(targetManagement.findAllTargetIds().size()); + assertThat(25).as("Targets with no tag").isEqualTo(targetsListWithNoTag.size()); + } } diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTargetFieldTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTargetFieldTest.java index 50b6600e9..2f77346f2 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTargetFieldTest.java +++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTargetFieldTest.java @@ -114,8 +114,9 @@ public class RSQLTargetFieldTest extends AbstractIntegrationTest { assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "!=pending", 3); try { assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "==noExist*", 0); - fail(); + fail("RSQLParameterUnsupportedFieldException was expected since update status unknown"); } catch (final RSQLParameterUnsupportedFieldException e) { + // test ok - exception was excepted } assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "=in=(pending,error)", 1); assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "=out=(pending,error)", 3); diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetRestApi.java b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetRestApi.java new file mode 100644 index 000000000..05d377950 --- /dev/null +++ b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetRestApi.java @@ -0,0 +1,365 @@ +/** + * 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.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.MetadataRestPageList; +import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetPagedList; +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.DistributionSetsRest; +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.SoftwareModulePagedList; +import org.eclipse.hawkbit.rest.resource.model.target.TargetPagedList; +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 DistributionSet CRUD operations. + */ +@RequestMapping(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING) +public interface DistributionSetRestApi { + + /** + * Handles the GET request of retrieving all DistributionSets . + * + * @param pagingOffsetParam + * the offset of list of sets for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * @return a list of all set for a defined or default page request with + * status OK. The response is always paged. In any failure the + * 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); + + /** + * Handles the GET request of retrieving a single DistributionSet . + * + * @param distributionSetId + * the ID of the set to retrieve + * + * @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( + @PathVariable("distributionSetId") final Long distributionSetId); + + /** + * Handles the POST request of creating new distribution sets . The request + * body must always be a list of sets. + * + * @param sets + * the DistributionSets to be created. + * @return In case all sets could successful created the ResponseEntity with + * status code 201 - Created but without ResponseBody. In any + * failure the JsonResponseExceptionHandler is handling the + * response. + */ + @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); + + /** + * Handles the DELETE request for a single DistributionSet . + * + * @param distributionSetId + * the ID of the DistributionSet to delete + * @return status OK if delete as successful. + * + */ + @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetId}") + public ResponseEntity deleteDistributionSet(@PathVariable("distributionSetId") final Long distributionSetId); + + /** + * Handles the UPDATE request for a single DistributionSet . + * + * @param distributionSetId + * the ID of the DistributionSet to delete + * @param toUpdate + * with the data that needs updating + * + * @return status OK if update as successful with updated content. + * + */ + @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( + @PathVariable("distributionSetId") final Long distributionSetId, + @RequestBody final DistributionSetRequestBodyPut toUpdate); + + /** + * Handles the GET request of retrieving assigned targets to a specific + * distribution set. + * + * @param distributionSetId + * the ID of the distribution set to retrieve the assigned + * targets + * @param pagingOffsetParam + * the offset of list of targets for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * @return status OK if get request is successful with the paged list of + * targets + */ + @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/assignedTargets", produces = { + MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) + public 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); + + /** + * Handles the GET request of retrieving installed targets to a specific + * distribution set. + * + * @param distributionSetId + * the ID of the distribution set to retrieve the assigned + * targets + * @param pagingOffsetParam + * the offset of list of targets for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * @return status OK if get request is successful with the paged list of + * targets + */ + @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/installedTargets", produces = { + MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) + public 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); + + /** + * Handles the POST request of assigning multiple targets to a single + * distribution set. + * + * @param distributionSetId + * the ID of the distribution set within the URL path parameter + * @param targetIds + * the IDs of the target which should get assigned to the + * distribution set given in the response body + * @return status OK if the assignment of the targets was successful and a + * complex return body which contains information about the assigned + * targets and the already assigned targets counters + */ + @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( + @PathVariable("distributionSetId") final Long distributionSetId, + @RequestBody final List targetIds); + + /** + * Gets a paged list of meta data for a distribution set. + * + * @param distributionSetId + * the ID of the distribution set for the meta data + * @param pagingOffsetParam + * the offset of list of targets for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=key==abc} + * @return status OK if get request is successful with the paged list of + * meta data + */ + @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); + + /** + * Gets a single meta data value for a specific key of a distribution set. + * + * @param distributionSetId + * the ID of the distribution set to get the meta data from + * @param metadataKey + * the key of the meta data entry to retrieve the value from + * @return status OK if get request is successful with the value of the meta + * data + */ + @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/metadata/{metadataKey}", produces = { + MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity getMetadataValue( + @PathVariable("distributionSetId") final Long distributionSetId, + @PathVariable("metadataKey") final String metadataKey); + + /** + * Updates a single meta data value of a distribution set. + * + * @param distributionSetId + * the ID of the distribution set to update the meta data entry + * @param metadataKey + * the key of the meta data to update the value + * @return status OK if the update request is successful and the updated + * meta data result + */ + @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); + + /** + * Deletes a single meta data entry from the distribution set. + * + * @param distributionSetId + * the ID of the distribution set to delete the meta data entry + * @param metadataKey + * the key of the meta data to delete + * @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, + @PathVariable("metadataKey") final String metadataKey); + + /** + * Creates a list of meta data for a specific distribution set. + * + * @param distributionSetId + * the ID of the distribution set to create meta data for + * @param metadataRest + * the list of meta data entries to create + * @return status created if post request is successful with the value of + * the created meta data + */ + @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); + + /** + * Assigns a list of software modules to a distribution set. + * + * @param distributionSetId + * the ID of the distribution set to assign software modules for + * @param softwareModuleIDs + * 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); + + /** + * Deletes the assignment of the software module form the distribution set. + * + * @param distributionSetId + * the ID of the distribution set to reject the software module + * for + * @param softwareModuleId + * 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, + @PathVariable("softwareModuleId") final Long softwareModuleId); + + /** + * Handles the GET request for retrieving the assigned software modules of a + * specific distribution set. + * + * @param distributionSetId + * the ID of the distribution to retrieve + * @param pagingOffsetParam + * the offset of list of sets for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@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( + @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); +} diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetTagRestApi.java b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetTagRestApi.java new file mode 100644 index 000000000..d99368dc2 --- /dev/null +++ b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetTagRestApi.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.rest.resource.api; + +import java.util.List; + +import org.eclipse.hawkbit.rest.resource.RestConstants; +import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest; +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.TagPagedList; +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.TagsRest; +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 DistributionSetTag CRUD operations. + * + */ +@RequestMapping(RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING) +public interface DistributionSetTagRestApi { + /** + * Handles the GET request of retrieving all DistributionSet tags. + * + * @param pagingOffsetParam + * the offset of list of DistributionSet tags for pagination, + * might not be present in the rest request then default value + * will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * @return a list of all target tags for a defined or default page request + * with status OK. The response is always paged. In any failure the + * 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); + + /** + * Handles the GET request of retrieving a single distribution set tag. + * + * @param distributionsetTagId + * 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( + @PathVariable("distributionsetTagId") final Long distributionsetTagId); + + /** + * Handles the POST request of creating new distribution set tag. The + * request body must always be a list of tags. + * + * @param tags + * the distribution set tags to be created. + * @return In case all modules could successful created the ResponseEntity + * with status code 201 - Created. The Response Body are the created + * distribution set tags but without ResponseBody. + */ + @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); + + /** + * + * Handles the PUT request of updating a single distribution set tag. + * + * @param distributionsetTagId + * the ID of the distribution set tag + * @param restDSTagRest + * 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( + @PathVariable("distributionsetTagId") final Long distributionsetTagId, + @RequestBody final TagRequestBodyPut restDSTagRest); + + /** + * Handles the DELETE request for a single distribution set tag. + * + * @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( + @PathVariable("distributionsetTagId") final Long distributionsetTagId); + + /** + * Handles the GET request of retrieving all assigned distribution sets by + * the given tag id. + * + * @param distributionsetTagId + * 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( + @PathVariable("distributionsetTagId") final Long distributionsetTagId); + + /** + * Handles the POST request to toggle the assignment of distribution sets by + * the given tag id. + * + * @param distributionsetTagIds + * the ID of the distribution set tag to retrieve + * @param assignedDSRequestBodies + * list of distribution set ids to be toggled + * + * @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 + + "/toggleTagAssignment") + public ResponseEntity toggleTagAssignment( + @PathVariable("distributionsetTagId") final Long distributionsetTagId, + @RequestBody final List assignedDSRequestBodies); + + /** + * Handles the POST request to assign distribution sets to the given tag id. + * + * @param distributionsetTagId + * the ID of the distribution set tag to retrieve + * @param assignedDSRequestBodies + * 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( + @PathVariable("distributionsetTagId") final Long distributionsetTagId, + @RequestBody final List assignedDSRequestBodies); + + /** + * Handles the DELETE request to unassign all distribution set from the + * given tag id. + * + * @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( + @PathVariable("distributionsetTagId") final Long distributionsetTagId); + + /** + * Handles the DELETE request to unassign one distribution set from the + * given tag id. + * + * @param distributionsetTagId + * the ID of the distribution set tag + * @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 + + "/{distributionsetId}") + public 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-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetTypeRestApi.java new file mode 100644 index 000000000..9bed7f4f8 --- /dev/null +++ b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/DistributionSetTypeRestApi.java @@ -0,0 +1,259 @@ +/** + * 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.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.distributionsettype.DistributionSetTypePagedList; +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.distributionsettype.DistributionSetTypesRest; +import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRest; +import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypesRest; +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 SoftwareModule and related Artifact CRUD + * operations. + * + */ +@RequestMapping(RestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING) +public interface DistributionSetTypeRestApi { + + /** + * Handles the GET request of retrieving all DistributionSetTypes. + * + * @param pagingOffsetParam + * the offset of list of modules for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * + * @return a list of all DistributionSetType for a defined or default page + * request with status OK. The response is always paged. In any + * failure the JsonResponseExceptionHandler is handling the + * 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); + + /** + * Handles the GET request of retrieving a single DistributionSetType + * within. + * + * @param distributionSetTypeId + * 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( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId); + + /** + * Handles the DELETE request for a single Distribution Set Type. + * + * @param distributionSetTypeId + * the ID of the module to retrieve + * @return status OK if delete as sucessfull. + * + */ + @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetTypeId}") + public ResponseEntity deleteDistributionSetType( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId); + + /** + * Handles the PUT request of updating a Distribution Set Type. + * + * @param distributionSetTypeId + * the ID of the software module in the URL + * @param restDistributionSetType + * the module type to be updated. + * @return status OK if update is successful + */ + @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( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @RequestBody final DistributionSetTypeRequestBodyPut restDistributionSetType); + + /** + * Handles the POST request of creating new DistributionSetTypes. The + * request body must always be a list of types. + * + * @param distributionSetTypes + * the modules to be created. + * @return In case all modules could successful created the ResponseEntity + * with status code 201 - Created but without ResponseBody. In any + * failure the JsonResponseExceptionHandler is handling the + * response. + */ + @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); + + /** + * Handles the GET request of retrieving the list of mandatory software + * module types in that distribution set type. + * + * @param distributionSetTypeId + * of the DistributionSetType. + * @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", + MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity getMandatoryModules( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId); + + /** + * Handles the GET request of retrieving the single mandatory software + * module type in that distribution set type. + * + * @param distributionSetTypeId + * of the DistributionSetType. + * @param softwareModuleTypeId + * of SoftwareModuleType. + * @return Unpaged list of module types and OK in case of success. + */ + @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetTypeId}/" + + RestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES + + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity getMandatoryModule( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); + + /** + * Handles the GET request of retrieving the single optional software module + * type in that distribution set type. + * + * @param distributionSetTypeId + * of the DistributionSetType. + * @param softwareModuleTypeId + * of SoftwareModuleType. + * @return Unpaged list of module types and OK in case of success. + */ + @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetTypeId}/" + + RestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES + + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity getOptionalModule( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); + + /** + * Handles the GET request of retrieving the list of optional software + * module types in that distribution set type. + * + * @param distributionSetTypeId + * of the DistributionSetType. + * @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", + MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity getOptionalModules( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId); + + /** + * Handles DELETE request for removing a mandatory module from the + * DistributionSetType. + * + * @param distributionSetTypeId + * of the DistributionSetType. + * @param softwareModuleTypeId + * of the SoftwareModuleType to remove + * + * @return OK if the request was successful + */ + @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetTypeId}/" + + RestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES + + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity removeMandatoryModule( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); + + /** + * Handles DELETE request for removing an optional module from the + * DistributionSetType. + * + * @param distributionSetTypeId + * of the DistributionSetType. + * @param softwareModuleTypeId + * of the SoftwareModuleType to remove + * + * @return OK if the request was successful + */ + @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetTypeId}/" + + RestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES + + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity removeOptionalModule( + @PathVariable("distributionSetTypeId") final Long distributionSetTypeId, + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); + + /** + * Handles the POST request for adding a mandatory software module type to a + * distribution set type. + * + * @param distributionSetTypeId + * of the DistributionSetType. + * @param smtId + * of the SoftwareModuleType to add + * + * @return OK if the request was successful + */ + @RequestMapping(method = RequestMethod.POST, value = "/{distributionSetTypeId}/" + + RestConstants.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); + + /** + * Handles the POST request for adding an optional software module type to a + * distribution set type. + * + * @param distributionSetTypeId + * of the DistributionSetType. + * @param smtId + * of the SoftwareModuleType to add + * + * @return OK if the request was successful + */ + @RequestMapping(method = RequestMethod.POST, value = "/{distributionSetTypeId}/" + + RestConstants.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); + +} diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/RolloutRestApi.java b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/RolloutRestApi.java new file mode 100644 index 000000000..fe1c7caa5 --- /dev/null +++ b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/RolloutRestApi.java @@ -0,0 +1,209 @@ +/** + * 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.api; + +import org.eclipse.hawkbit.rest.resource.RestConstants; +import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutPagedList; +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.RolloutGroupPagedList; +import org.eclipse.hawkbit.rest.resource.model.rolloutgroup.RolloutGroupResponseBody; +import org.eclipse.hawkbit.rest.resource.model.target.TargetPagedList; +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 rollout CRUD operations. + * + */ +@RequestMapping(RestConstants.ROLLOUT_V1_REQUEST_MAPPING) +public interface RolloutRestApi { + + /** + * Handles the GET request of retrieving all rollouts. + * + * @param pagingOffsetParam + * the offset of list of rollouts for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * @return a list of all rollouts for a defined or default page request with + * status OK. The response is always paged. In any failure the + * 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); + + /** + * Handles the GET request of retrieving a single rollout. + * + * @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); + + /** + * Handles the POST request for creating rollout. + * + * @param rollout + * the rollout body to be created. + * @return In case rollout could successful created the ResponseEntity with + * 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); + + /** + * Handles the POST request for starting a rollout. + * + * @param rolloutId + * 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); + + /** + * Handles the POST request for pausing a rollout. + * + * @param rolloutId + * 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); + + /** + * Handles the POST request for resuming a rollout. + * + * @param rolloutId + * 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); + + /** + * Handles the GET request of retrieving all rollout groups referred to a + * rollout. + * + * @param pagingOffsetParam + * the offset of list of rollout groups for pagination, might not + * be present in the rest request then default value will be + * applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * @return a list of all rollout groups referred to a rollout for a defined + * or default page request with status OK. The response is always + * paged. In any failure the JsonResponseExceptionHandler is + * handling the response. + */ + @RequestMapping(method = RequestMethod.GET, value = "/{rolloutId}/deploygroups", produces = { + MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) + public 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); + + /** + * Handles the GET request for retrieving a single rollout group. + * + * @param rolloutId + * 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 + */ + @RequestMapping(method = RequestMethod.GET, value = "/{rolloutId}/deploygroups/{groupId}", produces = { + MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) + public ResponseEntity getRolloutGroup(@PathVariable("rolloutId") final Long rolloutId, + @PathVariable("groupId") final Long groupId); + + /** + * Retrieves all targets related to a specific rollout group. + * + * @param rolloutId + * the ID of the rollout + * @param groupId + * the ID of the rollout group + * @param pagingOffsetParam + * the offset of list of rollout groups for pagination, might not + * be present in the rest request then default value will be + * applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * @return a paged list of targets related to a specific rollout and rollout + * group. + */ + @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, + @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); +} diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleRestAPI.java b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleRestAPI.java new file mode 100644 index 000000000..0662c43ba --- /dev/null +++ b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleRestAPI.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.rest.resource.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.MetadataRestPageList; +import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactRest; +import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactsRest; +import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModulePagedList; +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.rest.resource.model.softwaremodule.SoftwareModulesRest; +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.ResponseBody; +import org.springframework.web.multipart.MultipartFile; + +/** + * REST Resource handling for SoftwareModule and related Artifact CRUD + * operations. + * + */ +@RequestMapping(RestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) +public interface SoftwareModuleRestAPI { + + /** + * Handles POST request for artifact upload. + * + * @param softwareModuleId + * of the parent SoftwareModule + * @param file + * that has to be uploaded + * @param optionalFileName + * to override {@link MultipartFile#getOriginalFilename()} + * @param md5Sum + * checksum for uploaded content check + * @param sha1Sum + * checksum for uploaded content check + * + * @return In case all sets could successful be created the ResponseEntity + * with status code 201 - Created but without ResponseBody. In any + * failure the JsonResponseExceptionHandler is handling the + * response. + */ + @RequestMapping(method = RequestMethod.POST, value = "/{softwareModuleId}/artifacts", produces = { + "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + 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); + + /** + * Handles the GET request of retrieving all meta data of artifacts assigned + * to a software module. + * + * @param softwareModuleId + * of the parent SoftwareModule + * + * @return a list of all artifacts for a defined or default page request + * with status OK. The response is always paged. In any failure the + * JsonResponseExceptionHandler is handling the response. + */ + @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/artifacts", produces = { + "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @ResponseBody + public ResponseEntity getArtifacts(@PathVariable("softwareModuleId") final Long softwareModuleId); + + /** + * Handles the GET request of retrieving a single Artifact meta data + * request. + * + * @param softwareModuleId + * of the parent SoftwareModule + * @param artifactId + * of the related LocalArtifact + * + * @return responseEntity with status ok if successful + */ + @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, + @PathVariable("artifactId") final Long artifactId); + + /** + * Handles the DELETE request for a single SoftwareModule. + * + * @param softwareModuleId + * the ID of the module that has the artifact + * @param artifactId + * of the artifact to be deleted + * + * @return status OK if delete as successful. + */ + @RequestMapping(method = RequestMethod.DELETE, value = "/{softwareModuleId}/artifacts/{artifactId}") + @ResponseBody + public ResponseEntity deleteArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("artifactId") final Long artifactId); + + /** + * Handles the GET request of retrieving all softwaremodules. + * + * @param pagingOffsetParam + * the offset of list of modules for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * + * @return a list of all modules for a defined or default page request with + * status OK. The response is always paged. In any failure the + * 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); + + /** + * Handles the GET request of retrieving a single software module. + * + * @param softwareModuleId + * 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); + + /** + * Handles the POST request of creating new softwaremodules. The request + * body must always be a list of modules. + * + * @param softwareModules + * the modules to be created. + * @return In case all modules could successful created the ResponseEntity + * with status code 201 - Created but without ResponseBody. In any + * failure the JsonResponseExceptionHandler is handling the + * response. + */ + @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); + + /** + * Handles the PUT request of updating a software module. + * + * @param softwareModuleId + * the ID of the software module in the URL + * @param restSoftwareModule + * the modules to be updated. + * @return status OK if update is successful + */ + @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( + @PathVariable("softwareModuleId") final Long softwareModuleId, + @RequestBody final SoftwareModuleRequestBodyPut restSoftwareModule); + + /** + * Handles the DELETE request for a single softwaremodule. + * + * @param softwareModuleId + * the ID of the module to retrieve + * @return status OK if delete as sucessfull. + * + */ + @RequestMapping(method = RequestMethod.DELETE, value = "/{softwareModuleId}") + public ResponseEntity deleteSoftwareModule(@PathVariable("softwareModuleId") final Long softwareModuleId); + + /** + * Gets a paged list of meta data for a software module. + * + * @param softwareModuleId + * the ID of the software module for the meta data + * @param pagingOffsetParam + * the offset of list of meta data for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=key==abc} + * @return status OK if get request is successful with the paged list of + * meta data + */ + @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); + + /** + * Gets a single meta data value for a specific key of a software module. + * + * @param softwareModuleId + * the ID of the software module to get the meta data from + * @param metadataKey + * the key of the meta data entry to retrieve the value from + * @return status OK if get request is successful with the value of the meta + * data + */ + @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/metadata/{metadataKey}", produces = { + MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity getMetadataValue(@PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("metadataKey") final String metadataKey); + + /** + * Updates a single meta data value of a software module. + * + * @param softwareModuleId + * the ID of the software module to update the meta data entry + * @param metadataKey + * the key of the meta data to update the value + * @return status OK if the update request is successful and the updated + * meta data result + */ + @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); + + /** + * Deletes a single meta data entry from the software module. + * + * @param softwareModuleId + * the ID of the software module to delete the meta data entry + * @param metadataKey + * the key of the meta data to delete + * @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, + @PathVariable("metadataKey") final String metadataKey); + + /** + * Creates a list of meta data for a specific software module. + * + * @param softwareModuleId + * the ID of the distribution set to create meta data for + * @param metadataRest + * the list of meta data entries to create + * @return status created if post request is successful with the value of + * the created meta data + */ + @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); + +} diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleTypeRestApi.java b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleTypeRestApi.java new file mode 100644 index 000000000..0c4756a04 --- /dev/null +++ b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/SoftwareModuleTypeRestApi.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.rest.resource.api; + +import java.util.List; + +import org.eclipse.hawkbit.rest.resource.RestConstants; +import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypePagedList; +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.rest.resource.model.softwaremoduletype.SoftwareModuleTypesRest; +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 SoftwareModule and related Artifact CRUD + * operations. + * + */ +@RequestMapping(RestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING) +public interface SoftwareModuleTypeRestApi { + /** + * Handles the GET request of retrieving all SoftwareModuleTypes . + * + * @param pagingOffsetParam + * the offset of list of modules for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * + * @return a list of all module type for a defined or default page request + * with status OK. The response is always paged. In any failure the + * 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); + + /** + * Handles the GET request of retrieving a single software module type . + * + * @param softwareModuleTypeId + * 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( + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); + + /** + * Handles the DELETE request for a single software module type . + * + * @param softwareModuleTypeId + * the ID of the module to retrieve + * @return status OK if delete as successfully. + * + */ + @RequestMapping(method = RequestMethod.DELETE, value = "/{softwareModuleTypeId}") + public ResponseEntity deleteSoftwareModuleType( + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId); + + /** + * Handles the PUT request of updating a software module type . + * + * @param softwareModuleTypeId + * the ID of the software module in the URL + * @param restSoftwareModuleType + * the module type to be updated. + * @return status OK if update is successful + */ + @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( + @PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId, + @RequestBody final SoftwareModuleTypeRequestBodyPut restSoftwareModuleType); + + /** + * Handles the POST request of creating new SoftwareModuleTypes. The request + * body must always be a list of types. + * + * @param softwareModuleTypes + * the modules to be created. + * @return In case all modules could successful created the ResponseEntity + * with status code 201 - Created but without ResponseBody. In any + * failure the JsonResponseExceptionHandler is handling the + * response. + */ + @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); + +} diff --git a/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/TargetRestApi.java b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/TargetRestApi.java new file mode 100644 index 000000000..9d63a520f --- /dev/null +++ b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/TargetRestApi.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.rest.resource.api; + +import java.util.List; + +import org.eclipse.hawkbit.rest.resource.RestConstants; +import org.eclipse.hawkbit.rest.resource.model.action.ActionPagedList; +import org.eclipse.hawkbit.rest.resource.model.action.ActionRest; +import org.eclipse.hawkbit.rest.resource.model.action.ActionStatusPagedList; +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.TargetPagedList; +import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody; +import org.eclipse.hawkbit.rest.resource.model.target.TargetRest; +import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest; +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; + +/** + * Api for handling target operations. + */ +@RequestMapping(RestConstants.TARGET_V1_REQUEST_MAPPING) +public interface TargetRestApi { + + /** + * Handles the GET request of retrieving a single target. + * + * @param targetId + * 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", + MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity getTarget(@PathVariable("targetId") final String targetId); + + /** + * Handles the GET request of retrieving all targets. + * + * @param pagingOffsetParam + * the offset of list of targets for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * @return a list of all targets for a defined or default page request with + * status OK. The response is always paged. In any failure the + * JsonResponseExceptionHandler is handling the response. + */ + + @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); + + /** + * Handles the POST request of creating new targets. The request body must + * always be a list of targets. + * + * @param targets + * the targets to be created. + * @return In case all targets could successful created the ResponseEntity + * with status code 201 with a list of successfully created + * entities. In any failure the JsonResponseExceptionHandler is + * handling the response. + */ + @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); + + /** + * 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 + * the path parameter which contains the ID of the target + * @param targetRest + * the request body which contains the fields which should be + * updated, fields which are not given are ignored for the + * udpate. + * @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", + MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity updateTarget(@PathVariable("targetId") final String targetId, + @RequestBody final TargetRequestBody targetRest); + + /** + * Handles the DELETE request of deleting a target. + * + * @param targetId + * 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. + */ + @RequestMapping(method = RequestMethod.DELETE, value = "/{targetId}", produces = { "application/hal+json", + MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity deleteTarget(@PathVariable("targetId") final String targetId); + + /** + * Handles the GET request of retrieving the attributes of a specific + * target. + * + * @param targetId + * 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); + + /** + * Handles the GET request of retrieving the Actions of a specific target. + * + * @param targetId + * to load actions for + * @param pagingOffsetParam + * the offset of list of targets for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=status==pending} + * @return a list of all Actions for a defined or default page request with + * 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", + 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); + + /** + * Handles the GET request of retrieving a specific Actions of a specific + * Target. + * + * @param targetId + * to load the action for + * @param actionId + * to load + * @return the action + */ + @RequestMapping(method = RequestMethod.GET, value = "/{targetId}/actions/{actionId}", produces = { + "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity getAction(@PathVariable("targetId") final String targetId, + @PathVariable("actionId") final Long actionId); + + /** + * Handles the DELETE request of canceling an specific Actions of a specific + * Target. + * + * @param targetId + * 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, + @PathVariable("actionId") final Long actionId, + @RequestParam(value = "force", required = false, defaultValue = "false") final boolean force); + + /** + * Handles the GET request of retrieving the ActionStatus of a specific + * target and action. + * + * @param targetId + * of the the action + * @param actionId + * of the status we are intend to load + * @param pagingOffsetParam + * the offset of list of targets for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @return a list of all ActionStatus for a defined or default page request + * 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 = { + "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); + + /** + * Handles the GET request of retrieving the assigned distribution set of an + * specific target. + * + * @param targetId + * 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); + + /** + * Changes the assigned distribution set of a target. + * + * @param targetId + * 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", + MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity postAssignedDistributionSet(@PathVariable("targetId") final String targetId, + @RequestBody final DistributionSetAssigmentRest dsId); + + /** + * Handles the GET request of retrieving the installed distribution set of + * an specific target. + * + * @param targetId + * 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); + +} \ 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-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/TargetTagRestApi.java new file mode 100644 index 000000000..59770db08 --- /dev/null +++ b/hawkbit-rest-api/src/main/java/org/eclipse/hawkbit/rest/resource/api/TargetTagRestApi.java @@ -0,0 +1,196 @@ +/** + * 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.api; + +import java.util.List; + +import org.eclipse.hawkbit.rest.resource.RestConstants; +import org.eclipse.hawkbit.rest.resource.model.tag.AssignedTargetRequestBody; +import org.eclipse.hawkbit.rest.resource.model.tag.TagPagedList; +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.TagsRest; +import org.eclipse.hawkbit.rest.resource.model.tag.TargetTagAssigmentResultRest; +import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest; +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 TargetTag CRUD operations. + * + */ +@RequestMapping(RestConstants.TARGET_TAG_V1_REQUEST_MAPPING) +public interface TargetTagRestApi { + + /** + * Handles the GET request of retrieving all target tags. + * + * @param pagingOffsetParam + * the offset of list of target tags for pagination, might not be + * present in the rest request then default value will be applied + * @param pagingLimitParam + * the limit of the paged request, might not be present in the + * rest request then default value will be applied + * @param sortParam + * the sorting parameter in the request URL, syntax + * {@code field:direction, field:direction} + * @param rsqlParam + * the search parameter in the request URL, syntax + * {@code q=name==abc} + * @return a list of all target tags for a defined or default page request + * with status OK. The response is always paged. In any failure the + * 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); + + /** + * Handles the GET request of retrieving a single target tag. + * + * @param targetTagId + * 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); + + /** + * Handles the POST request of creating new target tag. The request body + * must always be a list of tags. + * + * @param tags + * the target tags to be created. + * @return In case all modules could successful created the ResponseEntity + * with status code 201 - Created. The Response Body are the created + * target tags but without ResponseBody. + */ + @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); + + /** + * + * Handles the PUT request of updating a single targetr tag. + * + * @param targetTagId + * the ID of the target tag + * @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); + + /** + * Handles the DELETE request for a single target tag. + * + * @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); + + /** + * Handles the GET request of retrieving all assigned targets by the given + * tag id. + * + * @param targetTagId + * 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); + + /** + * Handles the POST request to toggle the assignment of targets by the given + * tag id. + * + * @param targetTagId + * the ID of the target tag to retrieve + * @param assignedTargetRequestBodies + * 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 + + "/toggleTagAssignment") + public ResponseEntity toggleTagAssignment( + @PathVariable("targetTagId") final Long targetTagId, + @RequestBody final List assignedTargetRequestBodies); + + /** + * Handles the POST request to assign targets to the given tag id. + * + * @param targetTagId + * the ID of the target tag to retrieve + * @param assignedTargetRequestBodies + * 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); + + /** + * Handles the DELETE request to unassign all targets from the given tag id. + * + * @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); + + /** + * Handles the DELETE request to unassign one target from the given tag id. + * + * @param targetTagId + * the ID of the target tag + * @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 + + "/{controllerId}") + public ResponseEntity unassignTarget(@PathVariable("targetTagId") final Long targetTagId, + @PathVariable("controllerId") final String controllerId); +} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetMapper.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetMapper.java index 830b47798..9ae133dd5 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetMapper.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetMapper.java @@ -22,6 +22,8 @@ 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; @@ -169,13 +171,13 @@ public final class DistributionSetMapper { response.setRequiredMigrationStep(distributionSet.isRequiredMigrationStep()); response.add( - linkTo(methodOn(DistributionSetResource.class).getDistributionSet(response.getDsId())).withRel("self")); + linkTo(methodOn(DistributionSetRestApi.class).getDistributionSet(response.getDsId())).withRel("self")); response.add(linkTo( - methodOn(DistributionSetTypeResource.class).getDistributionSetType(distributionSet.getType().getId())) + methodOn(DistributionSetTypeRestApi.class).getDistributionSetType(distributionSet.getType().getId())) .withRel("type")); - response.add(linkTo(methodOn(DistributionSetResource.class).getMetadata(response.getDsId(), + 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)) .withRel("metadata")); diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetResource.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetResource.java index b0a245915..a4c71378d 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetResource.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetResource.java @@ -30,6 +30,7 @@ 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.MetadataRestPageList; @@ -51,25 +52,14 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; 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; /** * REST Resource handling for {@link DistributionSet} CRUD operations. - * - * - * - * */ @RestController -@RequestMapping(RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING) -public class DistributionSetResource { +public class DistributionSetResource implements DistributionSetRestApi { private static final Logger LOG = LoggerFactory.getLogger(DistributionSetResource.class); @Autowired @@ -90,32 +80,9 @@ public class DistributionSetResource { @Autowired private DistributionSetManagement distributionSetManagement; - /** - * Handles the GET request of retrieving all {@link DistributionSet}s within - * SP. - * - * @param pagingOffsetParam - * the offset of list of sets for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * @return a list of all set for a defined or default page request with - * status OK. The response is always paged. In any failure the - * 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) { + @Override + public ResponseEntity getDistributionSets(final int pagingOffsetParam, + final int pagingLimitParam, final String sortParam, final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -124,99 +91,51 @@ public class DistributionSetResource { final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting); final Page findDsPage; if (rsqlParam != null) { - findDsPage = distributionSetManagement.findDistributionSetsAll( + findDsPage = this.distributionSetManagement.findDistributionSetsAll( RSQLUtility.parse(rsqlParam, DistributionSetFields.class), pageable, false); } else { - findDsPage = distributionSetManagement.findDistributionSetsAll(pageable, false, null); + findDsPage = this.distributionSetManagement.findDistributionSetsAll(pageable, false, null); } final List rest = DistributionSetMapper.toResponseFromDsList(findDsPage.getContent()); return new ResponseEntity<>(new DistributionSetPagedList(rest, findDsPage.getTotalElements()), HttpStatus.OK); } - /** - * Handles the GET request of retrieving a single {@link DistributionSet} - * within SP. - * - * @param distributionSetId - * the ID of the set to retrieve - * - * @return a single {@link DistributionSet} with status OK. - * - * @throws EntityNotFoundException - * in case no {@link DistributionSet} with the given ID exists. - */ - @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}", produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getDistributionSet(@PathVariable final Long distributionSetId) { + @Override + public ResponseEntity getDistributionSet(final Long distributionSetId) { final DistributionSet foundDs = findDistributionSetWithExceptionIfNotFound(distributionSetId); return new ResponseEntity<>(DistributionSetMapper.toResponse(foundDs), HttpStatus.OK); } - /** - * Handles the POST request of creating new distribution sets within SP. The - * request body must always be a list of sets. The requests is delegating to - * the {@link SoftwareManagement#createDistributionSet(DistributionSet))}. - * - * @param sets - * the {@link DistributionSet}s to be created. - * @return In case all sets could successful created the ResponseEntity with - * status code 201 - Created but without ResponseBody. In any - * failure the JsonResponseExceptionHandler is handling the - * response. - */ - @RequestMapping(method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE, - "application/hal+json" }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity createDistributionSets( - @RequestBody final List sets) { + 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( - systemManagement.getTenantMetadata(currentTenant.getCurrentTenant()).getDefaultDsType().getKey())); + sets.stream().filter(ds -> ds.getType() == null).forEach(ds -> ds.setType(this.systemManagement + .getTenantMetadata(this.currentTenant.getCurrentTenant()).getDefaultDsType().getKey())); - final Iterable createdDSets = distributionSetManagement.createDistributionSets( - DistributionSetMapper.dsFromRequest(sets, softwareManagement, distributionSetManagement)); + final Iterable createdDSets = this.distributionSetManagement.createDistributionSets( + DistributionSetMapper.dsFromRequest(sets, this.softwareManagement, this.distributionSetManagement)); LOG.debug("{} distribution sets created, return status {}", sets.size(), HttpStatus.CREATED); return new ResponseEntity<>(DistributionSetMapper.toResponseDistributionSets(createdDSets), HttpStatus.CREATED); } - /** - * Handles the DELETE request for a single {@link DistributionSet} within - * SP. - * - * @param distributionSetId - * the ID of the {@link DistributionSet} to delete - * @return status OK if delete as successful. - * - */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetId}") - public ResponseEntity deleteDistributionSet(@PathVariable final Long distributionSetId) { + @Override + public ResponseEntity deleteDistributionSet(final Long distributionSetId) { final DistributionSet set = findDistributionSetWithExceptionIfNotFound(distributionSetId); - distributionSetManagement.deleteDistributionSet(set); + this.distributionSetManagement.deleteDistributionSet(set); return new ResponseEntity<>(HttpStatus.OK); } - /** - * Handles the UPDATE request for a single {@link DistributionSet} within - * SP. - * - * @param distributionSetId - * the ID of the {@link DistributionSet} to delete - * @param toUpdate - * with the data that needs updating - * - * @return status OK if update as successful with updated content. - * - */ - @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(@PathVariable final Long distributionSetId, - @RequestBody final DistributionSetRequestBodyPut toUpdate) { + @Override + public ResponseEntity updateDistributionSet(final Long distributionSetId, + final DistributionSetRequestBodyPut toUpdate) { final DistributionSet set = findDistributionSetWithExceptionIfNotFound(distributionSetId); if (toUpdate.getDescription() != null) { @@ -231,38 +150,13 @@ public class DistributionSetResource { set.setVersion(toUpdate.getVersion()); } return new ResponseEntity<>( - DistributionSetMapper.toResponse(distributionSetManagement.updateDistributionSet(set)), HttpStatus.OK); + DistributionSetMapper.toResponse(this.distributionSetManagement.updateDistributionSet(set)), + HttpStatus.OK); } - /** - * Handles the GET request of retrieving assigned targets to a specific - * distribution set. - * - * @param distributionSetId - * the ID of the distribution set to retrieve the assigned - * targets - * @param pagingOffsetParam - * the offset of list of targets for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * @return status OK if get request is successful with the paged list of - * targets - */ - @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/assignedTargets", produces = { - MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity getAssignedTargets(@PathVariable 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) { + @Override + public ResponseEntity getAssignedTargets(final Long distributionSetId, final int pagingOffsetParam, + final int pagingLimitParam, final String sortParam, final String rsqlParam) { // check if distribution set exists otherwise throw exception // immediately @@ -275,45 +169,19 @@ public class DistributionSetResource { final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting); final Page targetsAssignedDS; if (rsqlParam != null) { - targetsAssignedDS = targetManagement.findTargetByAssignedDistributionSet(distributionSetId, + targetsAssignedDS = this.targetManagement.findTargetByAssignedDistributionSet(distributionSetId, RSQLUtility.parse(rsqlParam, TargetFields.class), pageable); } else { - targetsAssignedDS = targetManagement.findTargetByAssignedDistributionSet(distributionSetId, pageable); + targetsAssignedDS = this.targetManagement.findTargetByAssignedDistributionSet(distributionSetId, pageable); } return new ResponseEntity<>(new TargetPagedList(TargetMapper.toResponse(targetsAssignedDS.getContent()), targetsAssignedDS.getTotalElements()), HttpStatus.OK); } - /** - * Handles the GET request of retrieving installed targets to a specific - * distribution set. - * - * @param distributionSetId - * the ID of the distribution set to retrieve the assigned - * targets - * @param pagingOffsetParam - * the offset of list of targets for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * @return status OK if get request is successful with the paged list of - * targets - */ - @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/installedTargets", produces = { - MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity getInstalledTargets(@PathVariable 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) { + @Override + public ResponseEntity getInstalledTargets(final Long distributionSetId, + final int pagingOffsetParam, final int pagingLimitParam, final String sortParam, final String rsqlParam) { // check if distribution set exists otherwise throw exception // immediately findDistributionSetWithExceptionIfNotFound(distributionSetId); @@ -325,36 +193,22 @@ public class DistributionSetResource { final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting); final Page targetsInstalledDS; if (rsqlParam != null) { - targetsInstalledDS = targetManagement.findTargetByInstalledDistributionSet(distributionSetId, + targetsInstalledDS = this.targetManagement.findTargetByInstalledDistributionSet(distributionSetId, RSQLUtility.parse(rsqlParam, TargetFields.class), pageable); } else { - targetsInstalledDS = targetManagement.findTargetByInstalledDistributionSet(distributionSetId, pageable); + targetsInstalledDS = this.targetManagement.findTargetByInstalledDistributionSet(distributionSetId, + pageable); } return new ResponseEntity<>(new TargetPagedList(TargetMapper.toResponse(targetsInstalledDS.getContent()), targetsInstalledDS.getTotalElements()), HttpStatus.OK); } - /** - * Handles the POST request of assigning multiple targets to a single - * distribution set. - * - * @param distributionSetId - * the ID of the distribution set within the URL path parameter - * @param targetIds - * the IDs of the target which should get assigned to the - * distribution set given in the response body - * @return status OK if the assignment of the targets was successful and a - * complex return body which contains information about the assigned - * targets and the already assigned targets counters - */ - @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(@PathVariable final Long distributionSetId, - @RequestBody final List targetIds) { + @Override + public ResponseEntity createAssignedTarget(final Long distributionSetId, + final List targetIds) { - final DistributionSetAssignmentResult assignDistributionSet = deployManagament.assignDistributionSet( + final DistributionSetAssignmentResult assignDistributionSet = this.deployManagament.assignDistributionSet( distributionSetId, targetIds.stream() .map(t -> new TargetWithActionType(t.getId(), @@ -364,33 +218,9 @@ public class DistributionSetResource { return new ResponseEntity<>(DistributionSetMapper.toResponse(assignDistributionSet), HttpStatus.OK); } - /** - * Gets a paged list of meta data for a distribution set. - * - * @param distributionSetId - * the ID of the distribution set for the meta data - * @param pagingOffsetParam - * the offset of list of targets for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=key==abc} - * @return status OK if get request is successful with the paged list of - * meta data - */ - @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/metadata", produces = { - MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity getMetadata(@PathVariable 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) { + @Override + public ResponseEntity getMetadata(final Long distributionSetId, final int pagingOffsetParam, + final int pagingLimitParam, final String sortParam, final String rsqlParam) { // check if distribution set exists otherwise throw exception // immediately @@ -404,11 +234,11 @@ public class DistributionSetResource { final Page metaDataPage; if (rsqlParam != null) { - metaDataPage = distributionSetManagement.findDistributionSetMetadataByDistributionSetId(distributionSetId, - RSQLUtility.parse(rsqlParam, DistributionSetMetadataFields.class), pageable); + metaDataPage = this.distributionSetManagement.findDistributionSetMetadataByDistributionSetId( + distributionSetId, RSQLUtility.parse(rsqlParam, DistributionSetMetadataFields.class), pageable); } else { - metaDataPage = distributionSetManagement.findDistributionSetMetadataByDistributionSetId(distributionSetId, - pageable); + metaDataPage = this.distributionSetManagement + .findDistributionSetMetadataByDistributionSetId(distributionSetId, pageable); } return new ResponseEntity<>( @@ -418,119 +248,59 @@ public class DistributionSetResource { } - /** - * Gets a single meta data value for a specific key of a distribution set. - * - * @param distributionSetId - * the ID of the distribution set to get the meta data from - * @param metadataKey - * the key of the meta data entry to retrieve the value from - * @return status OK if get request is successful with the value of the meta - * data - */ - @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/metadata/{metadataKey}", produces = { - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getMetadataValue(@PathVariable final Long distributionSetId, - @PathVariable final String metadataKey) { + @Override + public ResponseEntity getMetadataValue(final Long distributionSetId, final String metadataKey) { // check if distribution set exists otherwise throw exception // immediately final DistributionSet ds = findDistributionSetWithExceptionIfNotFound(distributionSetId); - final DistributionSetMetadata findOne = distributionSetManagement + final DistributionSetMetadata findOne = this.distributionSetManagement .findOne(new DsMetadataCompositeKey(ds, metadataKey)); return ResponseEntity. ok(DistributionSetMapper.toResponseDsMetadata(findOne)); } - /** - * Updates a single meta data value of a distribution set. - * - * @param distributionSetId - * the ID of the distribution set to update the meta data entry - * @param metadataKey - * the key of the meta data to update the value - * @return status OK if the update request is successful and the updated - * meta data result - */ - @RequestMapping(method = RequestMethod.PUT, value = "/{distributionSetId}/metadata/{metadataKey}", produces = { - MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity updateMetadata(@PathVariable final Long distributionSetId, - @PathVariable final String metadataKey, @RequestBody final MetadataRest metadata) { + @Override + public ResponseEntity updateMetadata(final Long distributionSetId, final String metadataKey, + final MetadataRest metadata) { // check if distribution set exists otherwise throw exception // immediately final DistributionSet ds = findDistributionSetWithExceptionIfNotFound(distributionSetId); - final DistributionSetMetadata updated = distributionSetManagement + final DistributionSetMetadata updated = this.distributionSetManagement .updateDistributionSetMetadata(new DistributionSetMetadata(metadataKey, ds, metadata.getValue())); return ResponseEntity.ok(DistributionSetMapper.toResponseDsMetadata(updated)); } - /** - * Deletes a single meta data entry from the distribution set. - * - * @param distributionSetId - * the ID of the distribution set to delete the meta data entry - * @param metadataKey - * the key of the meta data to delete - * @return status OK if the delete request is successful - */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetId}/metadata/{metadataKey}") - public ResponseEntity deleteMetadata(@PathVariable final Long distributionSetId, - @PathVariable final String metadataKey) { + @Override + public ResponseEntity deleteMetadata(final Long distributionSetId, final String metadataKey) { // check if distribution set exists otherwise throw exception // immediately final DistributionSet ds = findDistributionSetWithExceptionIfNotFound(distributionSetId); - distributionSetManagement.deleteDistributionSetMetadata(new DsMetadataCompositeKey(ds, metadataKey)); + this.distributionSetManagement.deleteDistributionSetMetadata(new DsMetadataCompositeKey(ds, metadataKey)); return ResponseEntity.ok().build(); } - /** - * Creates a list of meta data for a specific distribution set. - * - * @param distributionSetId - * the ID of the distribution set to create meta data for - * @param metadataRest - * the list of meta data entries to create - * @return status created if post request is successful with the value of - * the created meta data - */ - @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 final Long distributionSetId, - @RequestBody final List metadataRest) { + @Override + public ResponseEntity> createMetadata(final Long distributionSetId, + final List metadataRest) { // check if distribution set exists otherwise throw exception // immediately final DistributionSet ds = findDistributionSetWithExceptionIfNotFound(distributionSetId); - final List created = distributionSetManagement + final List created = this.distributionSetManagement .createDistributionSetMetadata(DistributionSetMapper.fromRequestDsMetadata(ds, metadataRest)); return new ResponseEntity<>(DistributionSetMapper.toResponseDsMetadata(created), HttpStatus.CREATED); } - /** - * Assigns a list of software modules to a distribution set. - * - * @param distributionSetId - * the ID of the distribution set to assign software modules for - * @param softwareModuleIDs - * the list of software modules ids to assign - * @return {@link HttpStatus#OK} - * - * @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 final Long distributionSetId, - @RequestBody final List softwareModuleIDs) { + @Override + public ResponseEntity assignSoftwareModules(final Long distributionSetId, + 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) { - final SoftwareModule softwareModule = softwareManagement.findSoftwareModuleById(sm.getId()); + final SoftwareModule softwareModule = this.softwareManagement.findSoftwareModuleById(sm.getId()); if (softwareModule != null) { softwareModuleToBeAssigned.add(softwareModule); } else { @@ -538,63 +308,23 @@ public class DistributionSetResource { } } // Add Softwaremodules to DisSet only if all of them were found - distributionSetManagement.assignSoftwareModules(ds, softwareModuleToBeAssigned); + this.distributionSetManagement.assignSoftwareModules(ds, softwareModuleToBeAssigned); return new ResponseEntity<>(HttpStatus.OK); } - /** - * Deletes the assignment of the software module form the distribution set. - * - * @param distributionSetId - * the ID of the distribution set to reject the software module - * for - * @param softwareModuleId - * 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 final Long distributionSetId, - @PathVariable final Long softwareModuleId) { + @Override + public ResponseEntity deleteAssignSoftwareModules(final Long distributionSetId, final Long softwareModuleId) { // check if distribution set and software module exist otherwise throw // exception immediately final DistributionSet ds = findDistributionSetWithExceptionIfNotFound(distributionSetId); final SoftwareModule sm = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId); - distributionSetManagement.unassignSoftwareModule(ds, sm); + this.distributionSetManagement.unassignSoftwareModule(ds, sm); return ResponseEntity.ok().build(); } - /** - * Handles the GET request for retrieving the assigned software modules of a - * specific distribution set. - * - * @param distributionSetId - * the ID of the distribution to retrieve - * @param pagingOffsetParam - * the offset of list of sets for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@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( - @PathVariable 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) { + @Override + public ResponseEntity getAssignedSoftwareModules(final Long distributionSetId, + final int pagingOffsetParam, final int pagingLimitParam, final String sortParam) { // check if distribution set exists otherwise throw exception // immediately final DistributionSet foundDs = findDistributionSetWithExceptionIfNotFound(distributionSetId); @@ -602,7 +332,7 @@ public class DistributionSetResource { final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); final Sort sorting = PagingUtility.sanitizeSoftwareModuleSortParam(sortParam); final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting); - final Page softwaremodules = softwareManagement.findSoftwareModuleByAssignedTo(pageable, + final Page softwaremodules = this.softwareManagement.findSoftwareModuleByAssignedTo(pageable, foundDs); return new ResponseEntity<>( new SoftwareModulePagedList(SoftwareModuleMapper.toResponse(softwaremodules.getContent()), @@ -611,7 +341,7 @@ public class DistributionSetResource { } private DistributionSet findDistributionSetWithExceptionIfNotFound(final Long distributionSetId) { - final DistributionSet set = distributionSetManagement.findDistributionSetById(distributionSetId); + final DistributionSet set = this.distributionSetManagement.findDistributionSetById(distributionSetId); if (set == null) { throw new EntityNotFoundException("DistributionSet with Id {" + distributionSetId + "} does not exist"); } @@ -620,7 +350,7 @@ public class DistributionSetResource { } private SoftwareModule findSoftwareModuleWithExceptionIfNotFound(final Long softwareModuleId) { - final SoftwareModule sm = softwareManagement.findSoftwareModuleById(softwareModuleId); + final SoftwareModule sm = this.softwareManagement.findSoftwareModuleById(softwareModuleId); if (sm == null) { throw new EntityNotFoundException("SoftwareModule with Id {" + softwareModuleId + "} does not exist"); } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTagResource.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTagResource.java index 99e22436e..c395863ab 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTagResource.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTagResource.java @@ -19,6 +19,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTagAssigmentResult; import org.eclipse.hawkbit.repository.rsql.RSQLUtility; +import org.eclipse.hawkbit.rest.resource.api.DistributionSetTagRestApi; import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest; import org.eclipse.hawkbit.rest.resource.model.tag.AssignedDistributionSetRequestBody; import org.eclipse.hawkbit.rest.resource.model.tag.DistributionSetTagAssigmentResultRest; @@ -34,13 +35,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; 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; /** @@ -48,8 +43,7 @@ import org.springframework.web.bind.annotation.RestController; * */ @RestController -@RequestMapping(RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING) -public class DistributionSetTagResource { +public class DistributionSetTagResource implements DistributionSetTagRestApi { private static final Logger LOG = LoggerFactory.getLogger(DistributionSetTagResource.class); @Autowired @@ -58,32 +52,9 @@ public class DistributionSetTagResource { @Autowired private DistributionSetManagement distributionSetManagement; - /** - * Handles the GET request of retrieving all DistributionSet tags. - * - * @param pagingOffsetParam - * the offset of list of DistributionSet tags for pagination, - * might not be present in the rest request then default value - * will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * @return a list of all target tags for a defined or default page request - * with status OK. The response is always paged. In any failure the - * 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) { + @Override + public ResponseEntity getDistributionSetTags(final int pagingOffsetParam, final int pagingLimitParam, + final String sortParam, final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -93,11 +64,11 @@ public class DistributionSetTagResource { final Slice findTargetsAll; final Long countTargetsAll; if (rsqlParam == null) { - findTargetsAll = tagManagement.findAllDistributionSetTags(pageable); - countTargetsAll = tagManagement.countTargetTags(); + findTargetsAll = this.tagManagement.findAllDistributionSetTags(pageable); + countTargetsAll = this.tagManagement.countTargetTags(); } else { - final Page findTargetPage = tagManagement + final Page findTargetPage = this.tagManagement .findAllDistributionSetTags(RSQLUtility.parse(rsqlParam, TagFields.class), pageable); countTargetsAll = findTargetPage.getTotalElements(); findTargetsAll = findTargetPage; @@ -108,141 +79,63 @@ public class DistributionSetTagResource { return new ResponseEntity<>(new TagPagedList(rest, countTargetsAll), HttpStatus.OK); } - /** - * Handles the GET request of retrieving a single distribution set tag. - * - * @param distributionsetTagId - * 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(@PathVariable final Long distributionsetTagId) { + @Override + public ResponseEntity getDistributionSetTag(final Long distributionsetTagId) { final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); return new ResponseEntity<>(TagMapper.toResponse(tag), HttpStatus.OK); } - /** - * Handles the POST request of creating new distribution set tag. The - * request body must always be a list of tags. - * - * @param tags - * the distribution set tags to be created. - * @return In case all modules could successful created the ResponseEntity - * with status code 201 - Created. The Response Body are the created - * distribution set tags but without ResponseBody. - */ - @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) { + @Override + public ResponseEntity createDistributionSetTags(final List tags) { LOG.debug("creating {} ds tags", tags.size()); - final List createdTags = tagManagement + final List createdTags = this.tagManagement .createDistributionSetTags(TagMapper.mapDistributionSetTagFromRequest(tags)); return new ResponseEntity<>(TagMapper.toResponseDistributionSetTag(createdTags), HttpStatus.CREATED); } - /** - * - * Handles the PUT request of updating a single distribution set tag. - * - * @param distributionsetTagId - * the ID of the distribution set tag - * @param restDSTagRest - * 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(@PathVariable final Long distributionsetTagId, - @RequestBody final TagRequestBodyPut restDSTagRest) { + @Override + public ResponseEntity updateDistributionSetTag(final Long distributionsetTagId, + final TagRequestBodyPut restDSTagRest) { LOG.debug("update {} ds tag", restDSTagRest); final DistributionSetTag distributionSetTag = findDistributionTagById(distributionsetTagId); TagMapper.updateTag(restDSTagRest, distributionSetTag); - final DistributionSetTag updateDistributionSetTag = tagManagement.updateDistributionSetTag(distributionSetTag); + final DistributionSetTag updateDistributionSetTag = this.tagManagement + .updateDistributionSetTag(distributionSetTag); LOG.debug("ds tag updated"); return new ResponseEntity<>(TagMapper.toResponse(updateDistributionSetTag), HttpStatus.OK); } - /** - * Handles the DELETE request for a single distribution set tag. - * - * @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(@PathVariable final Long distributionsetTagId) { + @Override + public ResponseEntity deleteDistributionSetTag(final Long distributionsetTagId) { LOG.debug("Delete {} distribution set tag", distributionsetTagId); final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); - tagManagement.deleteDistributionSetTag(tag.getName()); + this.tagManagement.deleteDistributionSetTag(tag.getName()); return new ResponseEntity<>(HttpStatus.OK); } - /** - * Handles the GET request of retrieving all assigned distribution sets by - * the given tag id. - * - * @param distributionsetTagId - * 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( - @PathVariable final Long distributionsetTagId) { + @Override + public ResponseEntity getAssignedDistributionSets(final Long distributionsetTagId) { final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); return new ResponseEntity<>( DistributionSetMapper.toResponseDistributionSets(tag.getAssignedToDistributionSet()), HttpStatus.OK); } - /** - * Handles the POST request to toggle the assignment of distribution sets by - * the given tag id. - * - * @param distributionsetTagIds - * the ID of the distribution set tag to retrieve - * @param assignedDSRequestBodies - * list of distribution set ids to be toggled - * - * @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 - + "/toggleTagAssignment") - public ResponseEntity toggleTagAssignment( - @PathVariable final Long distributionsetTagId, - @RequestBody final List assignedDSRequestBodies) { + @Override + public ResponseEntity toggleTagAssignment(final Long distributionsetTagId, + final List assignedDSRequestBodies) { LOG.debug("Toggle distribution set assignment {} for ds tag {}", assignedDSRequestBodies.size(), distributionsetTagId); final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); - final DistributionSetTagAssigmentResult assigmentResult = distributionSetManagement + final DistributionSetTagAssigmentResult assigmentResult = this.distributionSetManagement .toggleTagAssignment(findDistributionSetIds(assignedDSRequestBodies), tag.getName()); final DistributionSetTagAssigmentResultRest tagAssigmentResultRest = new DistributionSetTagAssigmentResultRest(); @@ -257,44 +150,20 @@ public class DistributionSetTagResource { return new ResponseEntity<>(tagAssigmentResultRest, HttpStatus.OK); } - /** - * Handles the POST request to assign distribution sets to the given tag id. - * - * @param distributionsetTagId - * the ID of the distribution set tag to retrieve - * @param assignedDSRequestBodies - * 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(@PathVariable final Long distributionsetTagId, - @RequestBody final List assignedDSRequestBodies) { + @Override + public ResponseEntity assignDistributionSets(final Long distributionsetTagId, + final List assignedDSRequestBodies) { LOG.debug("Assign DistributionSet {} for ds tag {}", assignedDSRequestBodies.size(), distributionsetTagId); final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); - final List assignedDs = distributionSetManagement + final List assignedDs = this.distributionSetManagement .assignTag(findDistributionSetIds(assignedDSRequestBodies), tag); LOG.debug("Assignd DistributionSet {}", assignedDs.size()); return new ResponseEntity<>(DistributionSetMapper.toResponseDistributionSets(assignedDs), HttpStatus.OK); } - /** - * Handles the DELETE request to unassign all distribution set from the - * given tag id. - * - * @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(@PathVariable final Long distributionsetTagId) { + @Override + public ResponseEntity unassignDistributionSets(final Long distributionsetTagId) { LOG.debug("Unassign all DS for ds tag {}", distributionsetTagId); final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); if (tag.getAssignedToDistributionSet() == null) { @@ -302,36 +171,22 @@ public class DistributionSetTagResource { return new ResponseEntity<>(HttpStatus.OK); } - final List distributionSets = distributionSetManagement.unAssignAllDistributionSetsByTag(tag); + final List distributionSets = this.distributionSetManagement + .unAssignAllDistributionSetsByTag(tag); LOG.debug("Unassigned ds {}", distributionSets.size()); return new ResponseEntity<>(HttpStatus.OK); } - /** - * Handles the DELETE request to unassign one distribution set from the - * given tag id. - * - * @param distributionsetTagId - * the ID of the distribution set tag - * @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 - + "/{distributionsetId}") - public ResponseEntity unassignDistributionSet(@PathVariable final Long distributionsetTagId, - @PathVariable final Long distributionsetId) { + @Override + public ResponseEntity unassignDistributionSet(final Long distributionsetTagId, final Long distributionsetId) { LOG.debug("Unassign ds {} for ds tag {}", distributionsetId, distributionsetTagId); final DistributionSetTag tag = findDistributionTagById(distributionsetTagId); - distributionSetManagement.unAssignTag(distributionsetId, tag); + this.distributionSetManagement.unAssignTag(distributionsetId, tag); return new ResponseEntity<>(HttpStatus.OK); } private DistributionSetTag findDistributionTagById(final Long distributionsetTagId) { - final DistributionSetTag tag = tagManagement.findDistributionSetTagById(distributionsetTagId); + final DistributionSetTag tag = this.tagManagement.findDistributionSetTagById(distributionsetTagId); if (tag == null) { throw new EntityNotFoundException("Distribution Tag with Id {" + distributionsetTagId + "} does not exist"); } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeMapper.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeMapper.java index 0550e0fc5..92923cb56 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeMapper.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeMapper.java @@ -18,6 +18,7 @@ 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; import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypesRest; @@ -101,13 +102,13 @@ final class DistributionSetTypeMapper { result.setKey(type.getKey()); result.setModuleId(type.getId()); - result.add(linkTo(methodOn(DistributionSetTypeResource.class).getDistributionSetType(result.getModuleId())) + result.add(linkTo(methodOn(DistributionSetTypeRestApi.class).getDistributionSetType(result.getModuleId())) .withRel("self")); - result.add(linkTo(methodOn(DistributionSetTypeResource.class).getMandatoryModules(result.getModuleId())) + result.add(linkTo(methodOn(DistributionSetTypeRestApi.class).getMandatoryModules(result.getModuleId())) .withRel(RestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULES)); - result.add(linkTo(methodOn(DistributionSetTypeResource.class).getOptionalModules(result.getModuleId())) + result.add(linkTo(methodOn(DistributionSetTypeRestApi.class).getOptionalModules(result.getModuleId())) .withRel(RestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULES)); return result; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeResource.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeResource.java index 19cf94f04..700ef3d96 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeResource.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DistributionSetTypeResource.java @@ -19,6 +19,7 @@ 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.distributionsettype.DistributionSetTypePagedList; import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPost; @@ -33,12 +34,9 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; 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; @@ -47,12 +45,9 @@ import org.springframework.web.bind.annotation.RestController; * {@link Artifact} CRUD operations. * * - * - * */ @RestController -@RequestMapping(RestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING) -public class DistributionSetTypeResource { +public class DistributionSetTypeResource implements DistributionSetTypeRestApi { @Autowired private SoftwareManagement softwareManagement; @@ -60,30 +55,7 @@ public class DistributionSetTypeResource { @Autowired private DistributionSetManagement distributionSetManagement; - /** - * Handles the GET request of retrieving all {@link DistributionSetType}s - * within SP. - * - * @param pagingOffsetParam - * the offset of list of modules for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * - * @return a list of all {@link DistributionSetType} for a defined or - * default page request with status OK. The response is always - * paged. In any failure the JsonResponseExceptionHandler is - * handling the response. - */ - @RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - + @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, @@ -112,19 +84,7 @@ public class DistributionSetTypeResource { return new ResponseEntity<>(new DistributionSetTypePagedList(rest, countModulesAll), HttpStatus.OK); } - /** - * Handles the GET request of retrieving a single - * {@link DistributionSetType} within SP. - * - * @param distributionSetTypeId - * 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 }) + @Override public ResponseEntity getDistributionSetType( @PathVariable final Long distributionSetTypeId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); @@ -132,15 +92,7 @@ public class DistributionSetTypeResource { return new ResponseEntity<>(DistributionSetTypeMapper.toResponse(foundType), HttpStatus.OK); } - /** - * Handles the DELETE request for a single Distribution Set Type within SP. - * - * @param distributionSetTypeId - * the ID of the module to retrieve - * @return status OK if delete as sucessfull. - * - */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetTypeId}") + @Override public ResponseEntity deleteDistributionSetType(@PathVariable final Long distributionSetTypeId) { final DistributionSetType module = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); @@ -149,17 +101,7 @@ public class DistributionSetTypeResource { return new ResponseEntity<>(HttpStatus.OK); } - /** - * Handles the PUT request of updating a Distribution Set Type within SP. - * - * @param distributionSetTypeId - * the ID of the software module in the URL - * @param restDistributionSetType - * the module type to be updated. - * @return status OK if update is successful - */ - @RequestMapping(method = RequestMethod.PUT, value = "/{distributionSetTypeId}", consumes = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity updateDistributionSetType( @PathVariable final Long distributionSetTypeId, @RequestBody final DistributionSetTypeRequestBodyPut restDistributionSetType) { @@ -176,19 +118,7 @@ public class DistributionSetTypeResource { return new ResponseEntity<>(DistributionSetTypeMapper.toResponse(updatedDistributionSetType), HttpStatus.OK); } - /** - * Handles the POST request of creating new {@link DistributionSetType}s - * within SP. The request body must always be a list of types. - * - * @param distributionSetTypes - * the modules to be created. - * @return In case all modules could successful created the ResponseEntity - * with status code 201 - Created but without ResponseBody. In any - * failure the JsonResponseExceptionHandler is handling the - * response. - */ - @RequestMapping(method = RequestMethod.POST, consumes = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity createDistributionSetTypes( @RequestBody final List distributionSetTypes) { @@ -208,17 +138,7 @@ public class DistributionSetTypeResource { return module; } - /** - * Handles the GET request of retrieving the list of mandatory software - * module types in that distribution set type. - * - * @param distributionSetTypeId - * of the {@link DistributionSetType}. - * @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", - MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity getMandatoryModules(@PathVariable final Long distributionSetTypeId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); @@ -229,19 +149,7 @@ public class DistributionSetTypeResource { return new ResponseEntity<>(rest, HttpStatus.OK); } - /** - * Handles the GET request of retrieving the single mandatory software - * module type in that distribution set type. - * - * @param distributionSetTypeId - * of the {@link DistributionSetType}. - * @param softwareModuleTypeId - * of {@link SoftwareModuleType}. - * @return Unpaged list of module types and OK in case of success. - */ - @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES - + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity getMandatoryModule(@PathVariable final Long distributionSetTypeId, @PathVariable final Long softwareModuleTypeId) { @@ -257,19 +165,7 @@ public class DistributionSetTypeResource { return new ResponseEntity<>(SoftwareModuleTypeMapper.toResponse(foundSmType), HttpStatus.OK); } - /** - * Handles the GET request of retrieving the single optional software module - * type in that distribution set type. - * - * @param distributionSetTypeId - * of the {@link DistributionSetType}. - * @param softwareModuleTypeId - * of {@link SoftwareModuleType}. - * @return Unpaged list of module types and OK in case of success. - */ - @RequestMapping(method = RequestMethod.GET, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES - + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity getOptionalModule(@PathVariable final Long distributionSetTypeId, @PathVariable final Long softwareModuleTypeId) { @@ -285,17 +181,7 @@ public class DistributionSetTypeResource { return new ResponseEntity<>(SoftwareModuleTypeMapper.toResponse(foundSmType), HttpStatus.OK); } - /** - * Handles the GET request of retrieving the list of optional software - * module types in that distribution set type. - * - * @param distributionSetTypeId - * of the {@link DistributionSetType}. - * @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", - MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity getOptionalModules(@PathVariable final Long distributionSetTypeId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); @@ -306,20 +192,7 @@ public class DistributionSetTypeResource { return new ResponseEntity<>(rest, HttpStatus.OK); } - /** - * Handles DELETE request for removing a mandatory module from the - * {@link DistributionSetType}. - * - * @param distributionSetTypeId - * of the {@link DistributionSetType}. - * @param softwareModuleTypeId - * of the {@link SoftwareModuleType} to remove - * - * @return OK if the request was successful - */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES - + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity removeMandatoryModule(@PathVariable final Long distributionSetTypeId, @PathVariable final Long softwareModuleTypeId) { @@ -339,20 +212,7 @@ public class DistributionSetTypeResource { return new ResponseEntity<>(HttpStatus.OK); } - /** - * Handles DELETE request for removing an optional module from the - * {@link DistributionSetType}. - * - * @param distributionSetTypeId - * of the {@link DistributionSetType}. - * @param softwareModuleTypeId - * of the {@link SoftwareModuleType} to remove - * - * @return OK if the request was successful - */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES - + "/{softwareModuleTypeId}", produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity removeOptionalModule(@PathVariable final Long distributionSetTypeId, @PathVariable final Long softwareModuleTypeId) { final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId); @@ -371,21 +231,7 @@ public class DistributionSetTypeResource { return new ResponseEntity<>(HttpStatus.OK); } - /** - * Handles the POST request for adding a mandatory software module type to a - * distribution set type. - * - * @param distributionSetTypeId - * of the {@link DistributionSetType}. - * @param smtId - * of the {@link SoftwareModuleType} to add - * - * @return OK if the request was successful - */ - @RequestMapping(method = RequestMethod.POST, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULE_TYPES, consumes = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity addMandatoryModule(@PathVariable final Long distributionSetTypeId, @RequestBody final IdRest smtId) { @@ -400,21 +246,7 @@ public class DistributionSetTypeResource { return new ResponseEntity<>(HttpStatus.OK); } - /** - * Handles the POST request for adding an optional software module type to a - * distribution set type. - * - * @param distributionSetTypeId - * of the {@link DistributionSetType}. - * @param smtId - * of the {@link SoftwareModuleType} to add - * - * @return OK if the request was successful - */ - @RequestMapping(method = RequestMethod.POST, value = "/{distributionSetTypeId}/" - + RestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULE_TYPES, consumes = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity addOptionalModule(@PathVariable final Long distributionSetTypeId, @RequestBody final IdRest smtId) { diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DownloadArtifactResource.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DownloadArtifactResource.java new file mode 100644 index 000000000..00f8f4756 --- /dev/null +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/DownloadArtifactResource.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.rest.resource; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; +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.springframework.beans.factory.annotation.Autowired; +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; + +/** + * @author Jonathan Knoblauch + * + */ +@RestController +@RequestMapping(RestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) +public class DownloadArtifactResource { + + @Autowired + private SoftwareManagement softwareManagement; + + @Autowired + private ArtifactManagement artifactManagement; + + /** + * 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 + public ResponseEntity downloadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("artifactId") final Long artifactId, final HttpServletResponse servletResponse, + final HttpServletRequest request) { + final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId); + + if (null == module || !module.getLocalArtifact(artifactId).isPresent()) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + final LocalArtifact artifact = module.getLocalArtifact(artifactId).get(); + final DbArtifact file = artifactManagement.loadLocalArtifactBinary(artifact); + + 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); + + } + + private SoftwareModule findSoftwareModuleWithExceptionIfNotFound(final Long softwareModuleId, + final Long artifactId) { + final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId); + if (module == null) { + throw new EntityNotFoundException("SoftwareModule with Id {" + softwareModuleId + "} does not exist"); + } else if (artifactId != null && !module.getLocalArtifact(artifactId).isPresent()) { + throw new EntityNotFoundException("Artifact with Id {" + artifactId + "} does not exist"); + } + return module; + } + +} diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutMapper.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutMapper.java index 712595638..c6be219ba 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutMapper.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutMapper.java @@ -23,6 +23,7 @@ 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; @@ -70,12 +71,12 @@ final class RolloutMapper { rollout.getTotalTargetCountStatus().getTotalTargetCountByStatus(status)); } - body.add(linkTo(methodOn(RolloutResource.class).getRollout(rollout.getId())).withRel("self")); - body.add(linkTo(methodOn(RolloutResource.class).start(rollout.getId(), false)).withRel("start")); - body.add(linkTo(methodOn(RolloutResource.class).start(rollout.getId(), true)).withRel("startAsync")); - body.add(linkTo(methodOn(RolloutResource.class).pause(rollout.getId())).withRel("pause")); - body.add(linkTo(methodOn(RolloutResource.class).resume(rollout.getId())).withRel("resume")); - body.add(linkTo(methodOn(RolloutResource.class).getRolloutGroups(rollout.getId(), + 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")); return body; @@ -115,8 +116,9 @@ final class RolloutMapper { body.setName(rolloutGroup.getName()); body.setRolloutGroupId(rolloutGroup.getId()); body.setStatus(rolloutGroup.getStatus().toString().toLowerCase()); - body.add(linkTo(methodOn(RolloutResource.class).getRolloutGroup(rolloutGroup.getRollout().getId(), - rolloutGroup.getId())).withRel("self")); + body.add(linkTo( + methodOn(RolloutRestApi.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-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutResource.java index d72db72f9..e00d07191 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutResource.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/RolloutResource.java @@ -27,6 +27,7 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessActi import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; 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.rollout.RolloutPagedList; import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutResponseBody; import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutRestRequestBody; @@ -40,13 +41,8 @@ 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.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; /** @@ -54,8 +50,9 @@ import org.springframework.web.bind.annotation.RestController; * */ @RestController -@RequestMapping(RestConstants.ROLLOUT_V1_REQUEST_MAPPING) -public class RolloutResource { +public class RolloutResource implements RolloutRestApi { + + private static final String DOES_NOT_EXIST = "} does not exist"; @Autowired private RolloutManagement rolloutManagement; @@ -66,31 +63,9 @@ public class RolloutResource { @Autowired private DistributionSetManagement distributionSetManagement; - /** - * Handles the GET request of retrieving all rollouts. - * - * @param pagingOffsetParam - * the offset of list of rollouts for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * @return a list of all rollouts for a defined or default page request with - * status OK. The response is always paged. In any failure the - * 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) { + @Override + public ResponseEntity getRollouts(final int pagingOffsetParam, final int pagingLimitParam, + final String sortParam, final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -100,50 +75,28 @@ public class RolloutResource { final Page findModulesAll; if (rsqlParam != null) { - findModulesAll = rolloutManagement + findModulesAll = this.rolloutManagement .findAllWithDetailedStatusByPredicate(RSQLUtility.parse(rsqlParam, RolloutFields.class), pageable); } else { - findModulesAll = rolloutManagement.findAll(pageable); + findModulesAll = this.rolloutManagement.findAll(pageable); } final List rest = RolloutMapper.toResponseRollout(findModulesAll.getContent()); return new ResponseEntity<>(new RolloutPagedList(rest, findModulesAll.getTotalElements()), HttpStatus.OK); } - /** - * Handles the GET request of retrieving a single rollout. - * - * @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) { + @Override + public ResponseEntity getRollout(final Long rolloutId) { final Rollout findRolloutById = findRolloutOrThrowException(rolloutId); return new ResponseEntity<>(RolloutMapper.toResponseRollout(findRolloutById), HttpStatus.OK); } - /** - * Handles the POST request for creating rollout. - * - * @param rollout - * the rollout body to be created. - * @return In case rollout could successful created the ResponseEntity with - * 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 }) + @Override public ResponseEntity create(@RequestBody final RolloutRestRequestBody rolloutRequestBody) { // first check the given RSQL query if it's well formed, otherwise and // exception is thrown - RSQLUtility.isValid(rolloutRequestBody.getTargetFilterQuery()); + RSQLUtility.parse(rolloutRequestBody.getTargetFilterQuery(), TargetFields.class); final DistributionSet distributionSet = findDistributionSetOrThrowException(rolloutRequestBody); @@ -181,7 +134,7 @@ public class RolloutResource { .successCondition(successCondition, successConditionExpr) .successAction(successAction, successActionExpr).errorCondition(errorCondition, errorConditionExpr) .errorAction(errorAction, errorActionExpr).build(); - final Rollout rollout = rolloutManagement.createRollout( + final Rollout rollout = this.rolloutManagement.createRollout( RolloutMapper.fromRequest(rolloutRequestBody, distributionSet, rolloutRequestBody.getTargetFilterQuery()), rolloutRequestBody.getAmountGroups(), rolloutGroupConditions); @@ -189,97 +142,34 @@ public class RolloutResource { return ResponseEntity.status(HttpStatus.CREATED).body(RolloutMapper.toResponseRollout(rollout)); } - /** - * Handles the POST request for starting a rollout. - * - * @param rolloutId - * 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) { + @Override + public ResponseEntity start(final Long rolloutId, final boolean startAsync) { final Rollout rollout = findRolloutOrThrowException(rolloutId); if (startAsync) { - rolloutManagement.startRolloutAsync(rollout); + this.rolloutManagement.startRolloutAsync(rollout); } else { - rolloutManagement.startRollout(rollout); + this.rolloutManagement.startRollout(rollout); } return ResponseEntity.ok().build(); } - /** - * Handles the POST request for pausing a rollout. - * - * @param rolloutId - * 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) { + @Override + public ResponseEntity pause(final Long rolloutId) { final Rollout rollout = findRolloutOrThrowException(rolloutId); - rolloutManagement.pauseRollout(rollout); + this.rolloutManagement.pauseRollout(rollout); return ResponseEntity.ok().build(); } - /** - * Handles the POST request for resuming a rollout. - * - * @param rolloutId - * 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) { + @Override + public ResponseEntity resume(final Long rolloutId) { final Rollout rollout = findRolloutOrThrowException(rolloutId); - rolloutManagement.resumeRollout(rollout); + this.rolloutManagement.resumeRollout(rollout); return ResponseEntity.ok().build(); } - /** - * Handles the GET request of retrieving all rollout groups referred to a - * rollout. - * - * @param pagingOffsetParam - * the offset of list of rollout groups for pagination, might not - * be present in the rest request then default value will be - * applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * @return a list of all rollout groups referred to a rollout for a defined - * or default page request with status OK. The response is always - * paged. In any failure the JsonResponseExceptionHandler is - * handling the response. - */ - @RequestMapping(method = RequestMethod.GET, value = "/{rolloutId}/deploygroups", produces = { - MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public 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) { + @Override + public ResponseEntity getRolloutGroups(final Long rolloutId, final int pagingOffsetParam, + final int pagingLimitParam, final String sortParam, final String rsqlParam) { final Rollout rollout = findRolloutOrThrowException(rolloutId); final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); @@ -290,10 +180,10 @@ public class RolloutResource { final Page findRolloutGroupsAll; if (rsqlParam != null) { - findRolloutGroupsAll = rolloutGroupManagement.findRolloutGroupsByPredicate(rollout, + findRolloutGroupsAll = this.rolloutGroupManagement.findRolloutGroupsByPredicate(rollout, RSQLUtility.parse(rsqlParam, RolloutGroupFields.class), pageable); } else { - findRolloutGroupsAll = rolloutGroupManagement.findRolloutGroupsByRolloutId(rolloutId, pageable); + findRolloutGroupsAll = this.rolloutGroupManagement.findRolloutGroupsByRolloutId(rolloutId, pageable); } final List rest = RolloutMapper @@ -302,56 +192,16 @@ public class RolloutResource { HttpStatus.OK); } - /** - * Handles the GET request for retrieving a single rollout group. - * - * @param rolloutId - * the rolloutId to retrieve the group from - * @param groupId - * the groupId to retrieve the rollout group - * @return the OK response containing the {@link RolloutGroupResponseBody} - * @throws EntityNotFoundException - */ - @RequestMapping(method = RequestMethod.GET, value = "/{rolloutId}/deploygroups/{groupId}", produces = { - MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) - public ResponseEntity getRolloutGroup(@PathVariable("rolloutId") final Long rolloutId, - @PathVariable("groupId") final Long groupId) { + @Override + public ResponseEntity getRolloutGroup(final Long rolloutId, final Long groupId) { findRolloutOrThrowException(rolloutId); final RolloutGroup rolloutGroup = findRolloutGroupOrThrowException(groupId); return ResponseEntity.ok(RolloutMapper.toResponseRolloutGroup(rolloutGroup)); } - /** - * Retrieves all targets related to a specific rollout group. - * - * @param rolloutId - * the ID of the rollout - * @param groupId - * the ID of the rollout group - * @param pagingOffsetParam - * the offset of list of rollout groups for pagination, might not - * be present in the rest request then default value will be - * applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * @return a paged list of targets related to a specific rollout and rollout - * group. - */ - @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, - @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) { + @Override + public ResponseEntity getRolloutGroupTargets(final Long rolloutId, final Long groupId, + final int pagingOffsetParam, final int pagingLimitParam, final String sortParam, final String rsqlParam) { findRolloutOrThrowException(rolloutId); final RolloutGroup rolloutGroup = findRolloutGroupOrThrowException(groupId); @@ -364,10 +214,11 @@ public class RolloutResource { final Page rolloutGroupTargets; if (rsqlParam != null) { final Specification rsqlSpecification = RSQLUtility.parse(rsqlParam, TargetFields.class); - rolloutGroupTargets = rolloutGroupManagement.findRolloutGroupTargets(rolloutGroup, rsqlSpecification, + rolloutGroupTargets = this.rolloutGroupManagement.findRolloutGroupTargets(rolloutGroup, rsqlSpecification, pageable); } else { - final Page pageTargets = rolloutGroupManagement.findRolloutGroupTargets(rolloutGroup, pageable); + final Page pageTargets = this.rolloutGroupManagement.findRolloutGroupTargets(rolloutGroup, + pageable); rolloutGroupTargets = pageTargets; } final List rest = TargetMapper.toResponse(rolloutGroupTargets.getContent()); @@ -375,27 +226,27 @@ public class RolloutResource { } private Rollout findRolloutOrThrowException(final Long rolloutId) { - final Rollout rollout = rolloutManagement.findRolloutWithDetailedStatus(rolloutId); + final Rollout rollout = this.rolloutManagement.findRolloutWithDetailedStatus(rolloutId); if (rollout == null) { - throw new EntityNotFoundException("Rollout with Id {" + rolloutId + "} does not exist"); + throw new EntityNotFoundException("Rollout with Id {" + rolloutId + DOES_NOT_EXIST); } return rollout; } private RolloutGroup findRolloutGroupOrThrowException(final Long rolloutGroupId) { - final RolloutGroup rolloutGroup = rolloutGroupManagement.findRolloutGroupById(rolloutGroupId); + final RolloutGroup rolloutGroup = this.rolloutGroupManagement.findRolloutGroupById(rolloutGroupId); if (rolloutGroup == null) { - throw new EntityNotFoundException("Group with Id {" + rolloutGroupId + "} does not exist"); + throw new EntityNotFoundException("Group with Id {" + rolloutGroupId + DOES_NOT_EXIST); } return rolloutGroup; } private DistributionSet findDistributionSetOrThrowException(final RolloutRestRequestBody rolloutRequestBody) { - final DistributionSet ds = distributionSetManagement + final DistributionSet ds = this.distributionSetManagement .findDistributionSetById(rolloutRequestBody.getDistributionSetId()); if (ds == null) { throw new EntityNotFoundException( - "DistributionSet with Id {" + rolloutRequestBody.getDistributionSetId() + "} does not exist"); + "DistributionSet with Id {" + rolloutRequestBody.getDistributionSetId() + DOES_NOT_EXIST); } return ds; } 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 index 947c216dd..1a3ce603f 100644 --- 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 @@ -21,6 +21,8 @@ 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; @@ -142,13 +144,13 @@ public final class SoftwareModuleMapper { response.setType(baseSofwareModule.getType().getKey()); response.setVendor(baseSofwareModule.getVendor()); - response.add(linkTo(methodOn(SoftwareModuleResource.class).getArtifacts(response.getModuleId())) + response.add(linkTo(methodOn(SoftwareModuleRestAPI.class).getArtifacts(response.getModuleId())) .withRel(RestConstants.SOFTWAREMODULE_V1_ARTIFACT)); - response.add(linkTo(methodOn(SoftwareModuleResource.class).getSoftwareModule(response.getModuleId())) + response.add(linkTo(methodOn(SoftwareModuleRestAPI.class).getSoftwareModule(response.getModuleId())) .withRel("self")); response.add(linkTo( - methodOn(SoftwareModuleTypeResource.class).getSoftwareModuleType(baseSofwareModule.getType().getId())) + methodOn(SoftwareModuleTypeRestApi.class).getSoftwareModuleType(baseSofwareModule.getType().getId())) .withRel(RestConstants.SOFTWAREMODULE_V1_TYPE)); response.add(linkTo(methodOn(SoftwareModuleResource.class).getMetadata(response.getModuleId(), @@ -178,13 +180,13 @@ public final class SoftwareModuleMapper { RestModelMapper.mapBaseToBase(artifactRest, artifact); - artifactRest.add(linkTo(methodOn(SoftwareModuleResource.class).getArtifact(artifact.getSoftwareModule().getId(), + artifactRest.add(linkTo(methodOn(SoftwareModuleRestAPI.class).getArtifact(artifact.getSoftwareModule().getId(), artifact.getId())).withRel("self")); if (artifact instanceof LocalArtifact) { - artifactRest.add( - linkTo(methodOn(SoftwareModuleResource.class).downloadArtifact(artifact.getSoftwareModule().getId(), - artifact.getId(), null, null)).withRel("download")); + artifactRest.add(linkTo(methodOn(DownloadArtifactResource.class) + .downloadArtifact(artifact.getSoftwareModule().getId(), artifact.getId(), null, null)) + .withRel("download")); } return artifactRest; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleResource.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleResource.java index 5c60334cd..9ce1a2975 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleResource.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleResource.java @@ -11,22 +11,17 @@ package org.eclipse.hawkbit.rest.resource; 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.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.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.SwMetadataCompositeKey; import org.eclipse.hawkbit.repository.rsql.RSQLUtility; -import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper; +import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleRestAPI; import org.eclipse.hawkbit.rest.resource.model.MetadataRest; import org.eclipse.hawkbit.rest.resource.model.MetadataRestPageList; import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactRest; @@ -44,14 +39,10 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; 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.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @@ -59,13 +50,9 @@ import org.springframework.web.multipart.MultipartFile; * REST Resource handling for {@link SoftwareModule} and related * {@link Artifact} CRUD operations. * - * - * - * */ @RestController -@RequestMapping(RestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING) -public class SoftwareModuleResource { +public class SoftwareModuleResource implements SoftwareModuleRestAPI { private static final Logger LOG = LoggerFactory.getLogger(SoftwareModuleResource.class); @Autowired @@ -74,25 +61,7 @@ public class SoftwareModuleResource { @Autowired private SoftwareManagement softwareManagement; - /** - * Handles POST request for artifact upload. - * - * @param softwareModuleId - * of the parent {@link SoftwareModule} - * @param file - * that has to be uploaded - * @param optionalFileName - * to override {@link MultipartFile#getOriginalFilename()} - * @param md5Sum - * checksum for uploaded content check - * @param sha1Sum - * checksum for uploaded content check - * - * @return {@link ResponseEntity} if status {@link HttpStatus#CREATED} if - * successful - */ - @RequestMapping(method = RequestMethod.POST, value = "/{softwareModuleId}/artifacts", produces = { - "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity uploadArtifact(@PathVariable final Long softwareModuleId, @RequestParam("file") final MultipartFile file, @RequestParam(value = "filename", required = false) final String optionalFileName, @@ -123,19 +92,7 @@ public class SoftwareModuleResource { } - /** - * Handles the GET request of retrieving all meta data of artifacts assigned - * to a software module. - * - * @param softwareModuleId - * of the parent {@link SoftwareModule} - * - * @return {@link ResponseEntity} with status {@link HttpStatus#OK} if - * successful - */ - @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/artifacts", produces = { - "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - @ResponseBody + @Override public ResponseEntity getArtifacts(@PathVariable final Long softwareModuleId) { final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); @@ -146,55 +103,49 @@ public class SoftwareModuleResource { * Handles the GET request for downloading an artifact. * * @param softwareModuleId - * of the parent {@link SoftwareModule} + * of the parent SoftwareModule * @param artifactId - * of the related {@link LocalArtifact} + * of the related LocalArtifact * @param servletResponse * of the servlet * @param request * of the client * - * @return {@link ResponseEntity} with status {@link HttpStatus#OK} if - * successful + * @return responseEntity with status ok if successful */ - @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/artifacts/{artifactId}/download") - @ResponseBody - public ResponseEntity downloadArtifact(@PathVariable final Long softwareModuleId, - @PathVariable final Long artifactId, final HttpServletResponse servletResponse, - final HttpServletRequest request) { - final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId); + // @RequestMapping(method = RequestMethod.GET, value = + // RestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + // + "/{softwareModuleId}/artifacts/{artifactId}/download") + // @ResponseBody + // public ResponseEntity downloadArtifact(@PathVariable final Long + // softwareModuleId, + // @PathVariable final Long artifactId, final HttpServletResponse + // servletResponse, + // final HttpServletRequest request) { + // final SoftwareModule module = + // findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId); + // + // if (null == module || !module.getLocalArtifact(artifactId).isPresent()) { + // return new ResponseEntity<>(HttpStatus.NOT_FOUND); + // } + // + // final LocalArtifact artifact = module.getLocalArtifact(artifactId).get(); + // final DbArtifact file = + // artifactManagement.loadLocalArtifactBinary(artifact); + // + // 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); + // + // } - if (null == module || !module.getLocalArtifact(artifactId).isPresent()) { - return new ResponseEntity<>(HttpStatus.NOT_FOUND); - } - - final LocalArtifact artifact = module.getLocalArtifact(artifactId).get(); - final DbArtifact file = artifactManagement.loadLocalArtifactBinary(artifact); - - 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); - - } - - /** - * Handles the GET request of retrieving a single Artifact meta data - * request. - * - * @param softwareModuleId - * of the parent {@link SoftwareModule} - * @param artifactId - * of the related {@link LocalArtifact} - * - * @return {@link ResponseEntity} with status {@link HttpStatus#OK} if - * successful - */ - @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/artifacts/{artifactId}", produces = { - "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - @ResponseBody + @Override public ResponseEntity getArtifact(@PathVariable final Long softwareModuleId, @PathVariable final Long artifactId) { final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId); @@ -203,18 +154,7 @@ public class SoftwareModuleResource { HttpStatus.OK); } - /** - * Handles the DELETE request for a single SoftwareModule within SP. - * - * @param softwareModuleId - * the ID of the module that has the artifact - * @param artifactId - * of the artifact to be deleted - * - * @return status OK if delete as successful. - */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{softwareModuleId}/artifacts/{artifactId}") - @ResponseBody + @Override public ResponseEntity deleteArtifact(@PathVariable final Long softwareModuleId, @PathVariable final Long artifactId) { findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId); @@ -225,27 +165,7 @@ public class SoftwareModuleResource { } - /** - * Handles the GET request of retrieving all softwaremodules within SP. - * - * @param pagingOffsetParam - * the offset of list of modules for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * - * @return a list of all modules for a defined or default page request with - * status OK. The response is always paged. In any failure the - * JsonResponseExceptionHandler is handling the response. - */ - @RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @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, @@ -273,38 +193,14 @@ public class SoftwareModuleResource { return new ResponseEntity<>(new SoftwareModulePagedList(rest, countModulesAll), HttpStatus.OK); } - /** - * Handles the GET request of retrieving a single software module within SP. - * - * @param softwareModuleId - * 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 }) + @Override public ResponseEntity getSoftwareModule(@PathVariable final Long softwareModuleId) { final SoftwareModule findBaseSoftareModule = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); return new ResponseEntity<>(SoftwareModuleMapper.toResponse(findBaseSoftareModule), HttpStatus.OK); } - /** - * Handles the POST request of creating new softwaremodules within SP. The - * request body must always be a list of modules. The requests is delgating - * to the {@link SoftwareManagement#createSoftwareModule(Iterable)}. - * - * @param softwareModules - * the modules to be created. - * @return In case all modules could successful created the ResponseEntity - * with status code 201 - Created but without ResponseBody. In any - * failure the JsonResponseExceptionHandler is handling the - * response. - */ - @RequestMapping(method = RequestMethod.POST, consumes = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity createSoftwareModules( @RequestBody final List softwareModules) { LOG.debug("creating {} softwareModules", softwareModules.size()); @@ -316,18 +212,7 @@ public class SoftwareModuleResource { HttpStatus.CREATED); } - /** - * Handles the PUT request of updating a software module within SP. - * {@link SoftwareManagement#createSoftwareModule(Iterable)}. - * - * @param softwareModuleId - * the ID of the software module in the URL - * @param restSoftwareModule - * the modules to be updated. - * @return status OK if update is successful - */ - @RequestMapping(method = RequestMethod.PUT, value = "/{softwareModuleId}", consumes = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity updateSoftwareModule(@PathVariable final Long softwareModuleId, @RequestBody final SoftwareModuleRequestBodyPut restSoftwareModule) { final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); @@ -344,15 +229,7 @@ public class SoftwareModuleResource { return new ResponseEntity<>(SoftwareModuleMapper.toResponse(updateSoftwareModule), HttpStatus.OK); } - /** - * Handles the DELETE request for a single softwaremodule within SP. - * - * @param softwareModuleId - * the ID of the module to retrieve - * @return status OK if delete as sucessfull. - * - */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{softwareModuleId}") + @Override public ResponseEntity deleteSoftwareModule(@PathVariable final Long softwareModuleId) { final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null); @@ -361,28 +238,7 @@ public class SoftwareModuleResource { return new ResponseEntity<>(HttpStatus.OK); } - /** - * Gets a paged list of meta data for a software module. - * - * @param softwareModuleId - * the ID of the software module for the meta data - * @param pagingOffsetParam - * the offset of list of meta data for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=key==abc} - * @return status OK if get request is successful with the paged list of - * meta data - */ - @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/metadata", produces = { - MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) + @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, @@ -412,18 +268,7 @@ public class SoftwareModuleResource { HttpStatus.OK); } - /** - * Gets a single meta data value for a specific key of a software module. - * - * @param softwareModuleId - * the ID of the software module to get the meta data from - * @param metadataKey - * the key of the meta data entry to retrieve the value from - * @return status OK if get request is successful with the value of the meta - * data - */ - @RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/metadata/{metadataKey}", produces = { - MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity getMetadataValue(@PathVariable final Long softwareModuleId, @PathVariable final String metadataKey) { // check if distribution set exists otherwise throw exception @@ -433,18 +278,7 @@ public class SoftwareModuleResource { return ResponseEntity. ok(SoftwareModuleMapper.toResponseSwMetadata(findOne)); } - /** - * Updates a single meta data value of a software module. - * - * @param softwareModuleId - * the ID of the software module to update the meta data entry - * @param metadataKey - * the key of the meta data to update the value - * @return status OK if the update request is successful and the updated - * meta data result - */ - @RequestMapping(method = RequestMethod.PUT, value = "/{softwareModuleId}/metadata/{metadataKey}", produces = { - MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) + @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 @@ -454,16 +288,7 @@ public class SoftwareModuleResource { return ResponseEntity.ok(SoftwareModuleMapper.toResponseSwMetadata(updated)); } - /** - * Deletes a single meta data entry from the software module. - * - * @param softwareModuleId - * the ID of the software module to delete the meta data entry - * @param metadataKey - * the key of the meta data to delete - * @return status OK if the delete request is successful - */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{softwareModuleId}/metadata/{metadataKey}") + @Override public ResponseEntity deleteMetadata(@PathVariable final Long softwareModuleId, @PathVariable final String metadataKey) { // check if software module exists otherwise throw exception immediately @@ -472,19 +297,7 @@ public class SoftwareModuleResource { return ResponseEntity.ok().build(); } - /** - * Creates a list of meta data for a specific software module. - * - * @param softwareModuleId - * the ID of the distribution set to create meta data for - * @param metadataRest - * the list of meta data entries to create - * @return status created if post request is successful with the value of - * the created meta data - */ - @RequestMapping(method = RequestMethod.POST, value = "/{softwareModuleId}/metadata", consumes = { - MediaType.APPLICATION_JSON_VALUE, - "application/hal+json" }, produces = { MediaType.APPLICATION_JSON_VALUE, "application/hal+json" }) + @Override public ResponseEntity> createMetadata(@PathVariable final Long softwareModuleId, @RequestBody final List metadataRest) { // check if software module exists otherwise throw exception immediately 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 index d187aa63a..5a05133b2 100644 --- 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 @@ -16,6 +16,7 @@ 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; import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypesRest; @@ -73,7 +74,7 @@ final class SoftwareModuleTypeMapper { result.setMaxAssignments(type.getMaxAssignments()); result.setModuleId(type.getId()); - result.add(linkTo(methodOn(SoftwareModuleTypeResource.class).getSoftwareModuleType(result.getModuleId())) + result.add(linkTo(methodOn(SoftwareModuleTypeRestApi.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-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeResource.java index 621efc690..c989bf6ad 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeResource.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/SoftwareModuleTypeResource.java @@ -10,8 +10,6 @@ package org.eclipse.hawkbit.rest.resource; import java.util.List; -import javax.persistence.EntityManager; - import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; @@ -19,6 +17,7 @@ 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.softwaremoduletype.SoftwareModuleTypePagedList; import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPost; import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPut; @@ -30,59 +29,22 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; 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; /** * REST Resource handling for {@link SoftwareModule} and related * {@link Artifact} CRUD operations. * - * - * - * */ @RestController -@RequestMapping(RestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING) -public class SoftwareModuleTypeResource { +public class SoftwareModuleTypeResource implements SoftwareModuleTypeRestApi { @Autowired private SoftwareManagement softwareManagement; - @Autowired - private EntityManager entityManager; - - /** - * Handles the GET request of retrieving all {@link SoftwareModuleType}s - * within SP. - * - * @param pagingOffsetParam - * the offset of list of modules for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * - * @return a list of all module type for a defined or default page request - * with status OK. The response is always paged. In any failure the - * 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) { + @Override + public ResponseEntity getTypes(final int pagingOffsetParam, final int pagingLimitParam, + final String sortParam, final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -93,12 +55,12 @@ public class SoftwareModuleTypeResource { final Slice findModuleTypessAll; Long countModulesAll; if (rsqlParam != null) { - findModuleTypessAll = softwareManagement.findSoftwareModuleTypesByPredicate( + findModuleTypessAll = this.softwareManagement.findSoftwareModuleTypesByPredicate( RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class), pageable); countModulesAll = ((Page) findModuleTypessAll).getTotalElements(); } else { - findModuleTypessAll = softwareManagement.findSoftwareModuleTypesAll(pageable); - countModulesAll = softwareManagement.countSoftwareModuleTypesAll(); + findModuleTypessAll = this.softwareManagement.findSoftwareModuleTypesAll(pageable); + countModulesAll = this.softwareManagement.countSoftwareModuleTypesAll(); } final List rest = SoftwareModuleTypeMapper @@ -106,56 +68,25 @@ public class SoftwareModuleTypeResource { return new ResponseEntity<>(new SoftwareModuleTypePagedList(rest, countModulesAll), HttpStatus.OK); } - /** - * Handles the GET request of retrieving a single software module type - * within SP. - * - * @param softwareModuleTypeId - * 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(@PathVariable final Long softwareModuleTypeId) { + @Override + public ResponseEntity getSoftwareModuleType(final Long softwareModuleTypeId) { final SoftwareModuleType foundType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId); return new ResponseEntity<>(SoftwareModuleTypeMapper.toResponse(foundType), HttpStatus.OK); } - /** - * Handles the DELETE request for a single software module type within SP. - * - * @param softwareModuleTypeId - * the ID of the module to retrieve - * @return status OK if delete as sucessfull. - * - */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{softwareModuleTypeId}") - public ResponseEntity deleteSoftwareModuleType(@PathVariable final Long softwareModuleTypeId) { + @Override + public ResponseEntity deleteSoftwareModuleType(final Long softwareModuleTypeId) { final SoftwareModuleType module = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId); - softwareManagement.deleteSoftwareModuleType(module); + this.softwareManagement.deleteSoftwareModuleType(module); return new ResponseEntity<>(HttpStatus.OK); } - /** - * Handles the PUT request of updating a software module type within SP. - * - * @param softwareModuleTypeId - * the ID of the software module in the URL - * @param restSoftwareModuleType - * the module type to be updated. - * @return status OK if update is successful - */ - @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( - @PathVariable final Long softwareModuleTypeId, - @RequestBody final SoftwareModuleTypeRequestBodyPut restSoftwareModuleType) { + @Override + public ResponseEntity updateSoftwareModuleType(final Long softwareModuleTypeId, + final SoftwareModuleTypeRequestBodyPut restSoftwareModuleType) { final SoftwareModuleType type = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId); // only description can be modified @@ -163,27 +94,15 @@ public class SoftwareModuleTypeResource { type.setDescription(restSoftwareModuleType.getDescription()); } - final SoftwareModuleType updatedSoftwareModuleType = softwareManagement.updateSoftwareModuleType(type); + final SoftwareModuleType updatedSoftwareModuleType = this.softwareManagement.updateSoftwareModuleType(type); return new ResponseEntity<>(SoftwareModuleTypeMapper.toResponse(updatedSoftwareModuleType), HttpStatus.OK); } - /** - * Handles the POST request of creating new {@link SoftwareModuleType}s - * within SP. The request body must always be a list of types. - * - * @param softwareModuleTypes - * the modules to be created. - * @return In case all modules could successful created the ResponseEntity - * with status code 201 - Created but without ResponseBody. In any - * failure the JsonResponseExceptionHandler is handling the - * response. - */ - @RequestMapping(method = RequestMethod.POST, consumes = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity createSoftwareModuleTypes( - @RequestBody final List softwareModuleTypes) { + final List softwareModuleTypes) { - final List createdSoftwareModules = softwareManagement + final List createdSoftwareModules = this.softwareManagement .createSoftwareModuleTypes(SoftwareModuleTypeMapper.smFromRequest(softwareModuleTypes)); return new ResponseEntity<>(SoftwareModuleTypeMapper.toTypesResponse(createdSoftwareModules), @@ -191,7 +110,7 @@ public class SoftwareModuleTypeResource { } private SoftwareModuleType findSoftwareModuleTypeWithExceptionIfNotFound(final Long softwareModuleTypeId) { - final SoftwareModuleType module = softwareManagement.findSoftwareModuleTypeById(softwareModuleTypeId); + final SoftwareModuleType module = this.softwareManagement.findSoftwareModuleTypeById(softwareModuleTypeId); if (module == null) { throw new EntityNotFoundException( "SoftwareModuleType with Id {" + softwareModuleTypeId + "} does not exist"); diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TagMapper.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TagMapper.java index 80a06ab2d..b5e84abe8 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TagMapper.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TagMapper.java @@ -17,6 +17,8 @@ import java.util.List; 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; import org.eclipse.hawkbit.rest.resource.model.tag.TagsRest; @@ -53,9 +55,9 @@ final class TagMapper { mapTag(response, targetTag); - response.add(linkTo(methodOn(TargetTagResource.class).getTargetTag(targetTag.getId())).withRel("self")); + response.add(linkTo(methodOn(TargetTagRestApi.class).getTargetTag(targetTag.getId())).withRel("self")); - response.add(linkTo(methodOn(TargetTagResource.class).getAssignedTargets(targetTag.getId())) + response.add(linkTo(methodOn(TargetTagRestApi.class).getAssignedTargets(targetTag.getId())) .withRel("assignedTargets")); return response; @@ -83,12 +85,11 @@ final class TagMapper { mapTag(response, distributionSetTag); - response.add( - linkTo(methodOn(DistributionSetTagResource.class).getDistributionSetTag(distributionSetTag.getId())) - .withRel("self")); + response.add(linkTo(methodOn(DistributionSetTagRestApi.class).getDistributionSetTag(distributionSetTag.getId())) + .withRel("self")); response.add(linkTo( - methodOn(DistributionSetTagResource.class).getAssignedDistributionSets(distributionSetTag.getId())) + methodOn(DistributionSetTagRestApi.class).getAssignedDistributionSets(distributionSetTag.getId())) .withRel("assignedDistributionSets")); return response; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetMapper.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetMapper.java index a79e136cb..4f6ddafb8 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetMapper.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetMapper.java @@ -23,6 +23,7 @@ import org.eclipse.hawkbit.repository.model.ActionStatus; 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; @@ -45,18 +46,18 @@ final public class TargetMapper { /** * Add links to a target response. - * + * * @param response * the target response */ public static void addTargetLinks(final TargetRest response) { - response.add(linkTo(methodOn(TargetResource.class).getAssignedDistributionSet(response.getControllerId())) + response.add(linkTo(methodOn(TargetRestApi.class).getAssignedDistributionSet(response.getControllerId())) .withRel(RestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET)); - response.add(linkTo(methodOn(TargetResource.class).getInstalledDistributionSet(response.getControllerId())) + response.add(linkTo(methodOn(TargetRestApi.class).getInstalledDistributionSet(response.getControllerId())) .withRel(RestConstants.TARGET_V1_INSTALLED_DISTRIBUTION_SET)); - response.add(linkTo(methodOn(TargetResource.class).getAttributes(response.getControllerId())) + response.add(linkTo(methodOn(TargetRestApi.class).getAttributes(response.getControllerId())) .withRel(RestConstants.TARGET_V1_ATTRIBUTES)); - response.add(linkTo(methodOn(TargetResource.class).getActionHistory(response.getControllerId(), 0, + response.add(linkTo(methodOn(TargetRestApi.class).getActionHistory(response.getControllerId(), 0, RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, ActionFields.ID.getFieldName() + ":" + SortDirection.DESC, null)) .withRel(RestConstants.TARGET_V1_ACTIONS)); @@ -64,7 +65,7 @@ final public class TargetMapper { /** * Add the pollstatus to a target response. - * + * * @param target * the target * @param targetRest @@ -85,7 +86,7 @@ final public class TargetMapper { /** * Create a response which includes links and pollstatus for all targets. - * + * * @param targets * the targets * @return the response @@ -105,7 +106,7 @@ final public class TargetMapper { /** * Create a response for targets. - * + * * @param targets * list of targets * @return the response @@ -123,7 +124,7 @@ final public class TargetMapper { /** * Create a response for target. - * + * * @param target * the target * @return the response @@ -163,7 +164,7 @@ final public class TargetMapper { targetRest.setInstalledAt(installationDate); } - targetRest.add(linkTo(methodOn(TargetResource.class).getTarget(target.getControllerId())).withRel("self")); + targetRest.add(linkTo(methodOn(TargetRestApi.class).getTarget(target.getControllerId())).withRel("self")); return targetRest; } @@ -210,7 +211,7 @@ final public class TargetMapper { RestModelMapper.mapBaseToBase(result, action); - result.add(linkTo(methodOn(TargetResource.class).getAction(targetId, action.getId())).withRel("self")); + result.add(linkTo(methodOn(TargetRestApi.class).getAction(targetId, action.getId())).withRel("self")); return result; } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetResource.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetResource.java index f50111db8..01f018327 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetResource.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetResource.java @@ -20,13 +20,14 @@ import org.eclipse.hawkbit.repository.ActionStatusFields; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.TargetFields; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException; 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.action.ActionPagedList; import org.eclipse.hawkbit.rest.resource.model.action.ActionRest; @@ -47,25 +48,15 @@ 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.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; /** * REST Resource handling target CRUD operations. - * - * - * - * */ @RestController -@RequestMapping(RestConstants.TARGET_V1_REQUEST_MAPPING) -public class TargetResource { +public class TargetResource implements TargetRestApi { private static final Logger LOG = LoggerFactory.getLogger(TargetResource.class); @Autowired @@ -74,18 +65,8 @@ public class TargetResource { @Autowired private DeploymentManagement deploymentManagement; - /** - * Handles the GET request of retrieving a single target within SP. - * - * @param targetId - * 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", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getTarget(@PathVariable final String targetId) { + @Override + public ResponseEntity getTarget(final String targetId) { final Target findTarget = findTargetWithExceptionIfNotFound(targetId); // to single response include poll status final TargetRest response = TargetMapper.toResponse(findTarget); @@ -95,31 +76,9 @@ public class TargetResource { return new ResponseEntity<>(response, HttpStatus.OK); } - /** - * Handles the GET request of retrieving all targets within SP. - * - * @param pagingOffsetParam - * the offset of list of targets for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * @return a list of all targets for a defined or default page request with - * status OK. The response is always paged. In any failure the - * JsonResponseExceptionHandler is handling the response. - */ - @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) { + @Override + public ResponseEntity getTargets(final int pagingOffsetParam, final int pagingLimitParam, + final String sortParam, final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -129,58 +88,29 @@ public class TargetResource { final Slice findTargetsAll; final Long countTargetsAll; if (rsqlParam != null) { - final Page findTargetPage = targetManagement + final Page findTargetPage = this.targetManagement .findTargetsAll(RSQLUtility.parse(rsqlParam, TargetFields.class), pageable); countTargetsAll = findTargetPage.getTotalElements(); findTargetsAll = findTargetPage; } else { - findTargetsAll = targetManagement.findTargetsAll(pageable); - countTargetsAll = targetManagement.countTargetsAll(); + findTargetsAll = this.targetManagement.findTargetsAll(pageable); + countTargetsAll = this.targetManagement.countTargetsAll(); } final List rest = TargetMapper.toResponse(findTargetsAll.getContent()); return new ResponseEntity<>(new TargetPagedList(rest, countTargetsAll), HttpStatus.OK); } - /** - * Handles the POST request of creating new targets within SP. The request - * body must always be a list of targets. The requests is delegating to the - * {@link TargetManagement#createTarget(Iterable)}. - * - * @param targets - * the targets to be created. - * @return In case all targets could successful created the ResponseEntity - * with status code 201 with a list of successfully created - * entities. In any failure the JsonResponseExceptionHandler is - * handling the response. - */ - @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) { + @Override + public ResponseEntity createTargets(final List targets) { LOG.debug("creating {} targets", targets.size()); - final Iterable createdTargets = targetManagement.createTargets(TargetMapper.fromRequest(targets)); + final Iterable createdTargets = this.targetManagement.createTargets(TargetMapper.fromRequest(targets)); LOG.debug("{} targets created, return status {}", targets.size(), HttpStatus.CREATED); return new ResponseEntity<>(TargetMapper.toResponse(createdTargets), HttpStatus.CREATED); } - /** - * Handles the PUT request of updating a target within SP. 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 - * the path parameter which contains the ID of the target - * @param targetRest - * the request body which contains the fields which should be - * updated, fields which are not given are ignored for the - * udpate. - * @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", - MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity updateTarget(@PathVariable final String targetId, - @RequestBody final TargetRequestBody targetRest) { + @Override + public ResponseEntity updateTarget(final String targetId, final TargetRequestBody targetRest) { final Target existingTarget = findTargetWithExceptionIfNotFound(targetId); LOG.debug("updating target {}", existingTarget.getId()); if (targetRest.getDescription() != null) { @@ -189,42 +119,21 @@ public class TargetResource { if (targetRest.getName() != null) { existingTarget.setName(targetRest.getName()); } - final Target updateTarget = targetManagement.updateTarget(existingTarget); + final Target updateTarget = this.targetManagement.updateTarget(existingTarget); return new ResponseEntity<>(TargetMapper.toResponse(updateTarget), HttpStatus.OK); } - /** - * Handles the DELETE request of deleting a target within SP. - * - * @param targetId - * 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. - */ - @RequestMapping(method = RequestMethod.DELETE, value = "/{targetId}", produces = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity deleteTarget(@PathVariable final String targetId) { + @Override + public ResponseEntity deleteTarget(final String targetId) { final Target target = findTargetWithExceptionIfNotFound(targetId); - targetManagement.deleteTargets(target.getId()); + this.targetManagement.deleteTargets(target.getId()); LOG.debug("{} target deleted, return status {}", targetId, HttpStatus.OK); return new ResponseEntity<>(HttpStatus.OK); } - /** - * Handles the GET request of retrieving the attributes of a specific - * target. - * - * @param targetId - * 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 final String targetId) { + @Override + public ResponseEntity getAttributes(final String targetId) { final Target foundTarget = findTargetWithExceptionIfNotFound(targetId); final Map controllerAttributes = foundTarget.getTargetInfo().getControllerAttributes(); if (controllerAttributes.isEmpty()) { @@ -237,36 +146,9 @@ public class TargetResource { return new ResponseEntity<>(result, HttpStatus.OK); } - /** - * Handles the GET request of retrieving the {@link Action}s of a specific - * target. - * - * @param targetId - * to load actions for - * @param pagingOffsetParam - * the offset of list of targets for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=status==pending} - * @return a list of all {@link Action}s for a defined or default page - * request with 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", - MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getActionHistory(@PathVariable 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) { + @Override + public ResponseEntity getActionHistory(final String targetId, final int pagingOffsetParam, + final int pagingLimitParam, final String sortParam, final String rsqlParam) { final Target foundTarget = findTargetWithExceptionIfNotFound(targetId); @@ -279,11 +161,11 @@ public class TargetResource { final Long totalActionCount; if (rsqlParam != null) { final Specification parse = RSQLUtility.parse(rsqlParam, ActionFields.class); - activeActions = deploymentManagement.findActionsByTarget(parse, foundTarget, pageable); - totalActionCount = deploymentManagement.countActionsByTarget(parse, foundTarget); + activeActions = this.deploymentManagement.findActionsByTarget(parse, foundTarget, pageable); + totalActionCount = this.deploymentManagement.countActionsByTarget(parse, foundTarget); } else { - activeActions = deploymentManagement.findActionsByTarget(foundTarget, pageable); - totalActionCount = deploymentManagement.countActionsByTarget(foundTarget); + activeActions = this.deploymentManagement.findActionsByTarget(foundTarget, pageable); + totalActionCount = this.deploymentManagement.countActionsByTarget(foundTarget); } return new ResponseEntity<>( @@ -291,20 +173,8 @@ public class TargetResource { HttpStatus.OK); } - /** - * Handles the GET request of retrieving a specific {@link Action}s of a - * specific {@link Target}. - * - * @param targetId - * to load the action for - * @param actionId - * to load - * @return the action - */ - @RequestMapping(method = RequestMethod.GET, value = "/{targetId}/actions/{actionId}", produces = { - "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getAction(@PathVariable final String targetId, - @PathVariable final Long actionId) { + @Override + public ResponseEntity getAction(final String targetId, final Long actionId) { final Target target = findTargetWithExceptionIfNotFound(targetId); final Action action = findActionWithExceptionIfNotFound(actionId); @@ -317,14 +187,14 @@ public class TargetResource { if (!action.isCancelingOrCanceled()) { result.add(linkTo( - methodOn(DistributionSetResource.class).getDistributionSet(action.getDistributionSet().getId())) + methodOn(DistributionSetRestApi.class).getDistributionSet(action.getDistributionSet().getId())) .withRel("distributionset")); } else if (action.isCancelingOrCanceled()) { - result.add(linkTo(methodOn(TargetResource.class).getAction(targetId, action.getId())) + result.add(linkTo(methodOn(TargetRestApi.class).getAction(targetId, action.getId())) .withRel(RestConstants.TARGET_V1_CANCELED_ACTION)); } - result.add(linkTo(methodOn(TargetResource.class).getActionStatusList(targetId, action.getId(), 0, + result.add(linkTo(methodOn(TargetRestApi.class).getActionStatusList(targetId, action.getId(), 0, RestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, ActionStatusFields.ID.getFieldName() + ":" + SortDirection.DESC)) .withRel(RestConstants.TARGET_V1_ACTION_STATUS)); @@ -332,32 +202,16 @@ public class TargetResource { return new ResponseEntity<>(result, HttpStatus.OK); } - /** - * Handles the DELETE request of canceling an specific {@link Action}s of a - * specific {@link Target}. - * - * @param targetId - * 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 final String targetId, @PathVariable final Long actionId, + @Override + public ResponseEntity cancelAction(final String targetId, final Long actionId, @RequestParam(required = false, defaultValue = "false") final boolean force) { final Target target = findTargetWithExceptionIfNotFound(targetId); final Action action = findActionWithExceptionIfNotFound(actionId); if (force) { - deploymentManagement.forceQuitAction(action, target); + this.deploymentManagement.forceQuitAction(action, target); } else { - deploymentManagement.cancelAction(action, target); + this.deploymentManagement.cancelAction(action, target); } // both functions will throw an exception, when action is in wrong // state, which is mapped by ResponseExceptionHandler. @@ -365,35 +219,9 @@ public class TargetResource { return new ResponseEntity<>(HttpStatus.NO_CONTENT); } - /** - * Handles the GET request of retrieving the {@link ActionStatus}s of a - * specific target and action. - * - * @param targetId - * of the the action - * @param actionId - * of the status we are intend to load - * @param pagingOffsetParam - * the offset of list of targets for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @return a list of all {@link ActionStatus}s for a defined or default page - * request 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 = { - "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity getActionStatusList(@PathVariable final String targetId, - @PathVariable 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) { + @Override + public ResponseEntity getActionStatusList(final String targetId, final Long actionId, + final int pagingOffsetParam, final int pagingLimitParam, final String sortParam) { final Target target = findTargetWithExceptionIfNotFound(targetId); @@ -407,7 +235,7 @@ public class TargetResource { final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); final Sort sorting = PagingUtility.sanitizeActionStatusSortParam(sortParam); - final Page statusList = deploymentManagement.findActionStatusMessagesByActionInDescOrder( + final Page statusList = this.deploymentManagement.findActionStatusMessagesByActionInDescOrder( new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting), action, true); return new ResponseEntity<>( @@ -417,20 +245,8 @@ public class TargetResource { } - /** - * Handles the GET request of retrieving the assigned distribution set of an - * specific target. - * - * @param targetId - * 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 final String targetId) { + @Override + public ResponseEntity getAssignedDistributionSet(final String targetId) { final Target findTarget = findTargetWithExceptionIfNotFound(targetId); final DistributionSetRest distributionSetRest = DistributionSetMapper .toResponse(findTarget.getAssignedDistributionSet()); @@ -443,28 +259,14 @@ public class TargetResource { return new ResponseEntity<>(distributionSetRest, retStatus); } - /** - * Changes the assigned distribution set of a target. - * - * @param targetId - * of the target to change - * @param dsId - * of the distributionset that is to be assigned - * @return {@link HttpStatus#OK} - * - * @throws EntityNotFoundException - * in case no target with the given {@code targetId} exists. - * - */ - @RequestMapping(method = RequestMethod.POST, value = "/{targetId}/assignedDS", consumes = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity postAssignedDistributionSet(@PathVariable final String targetId, - @RequestBody final DistributionSetAssigmentRest dsId) { + @Override + public ResponseEntity postAssignedDistributionSet(final String targetId, + final DistributionSetAssigmentRest dsId) { findTargetWithExceptionIfNotFound(targetId); final ActionType type = (dsId.getType() != null) ? RestResourceConversionHelper.convertActionType(dsId.getType()) : ActionType.FORCED; - final Iterator changed = deploymentManagement + final Iterator changed = this.deploymentManagement .assignDistributionSet(dsId.getId(), type, dsId.getForcetime(), targetId).getAssignedTargets() .iterator(); if (changed.hasNext()) { @@ -477,20 +279,8 @@ public class TargetResource { } - /** - * Handles the GET request of retrieving the installed distribution set of - * an specific target. - * - * @param targetId - * 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 final String targetId) { + @Override + public ResponseEntity getInstalledDistributionSet(final String targetId) { final Target findTarget = findTargetWithExceptionIfNotFound(targetId); final DistributionSetRest distributionSetRest = DistributionSetMapper .toResponse(findTarget.getTargetInfo().getInstalledDistributionSet()); @@ -504,7 +294,7 @@ public class TargetResource { } private Target findTargetWithExceptionIfNotFound(final String targetId) { - final Target findTarget = targetManagement.findTargetByControllerID(targetId); + final Target findTarget = this.targetManagement.findTargetByControllerID(targetId); if (findTarget == null) { throw new EntityNotFoundException("Target with Id {" + targetId + "} does not exist"); } @@ -512,7 +302,7 @@ public class TargetResource { } private Action findActionWithExceptionIfNotFound(final Long actionId) { - final Action findAction = deploymentManagement.findAction(actionId); + final Action findAction = this.deploymentManagement.findAction(actionId); if (findAction == null) { throw new EntityNotFoundException("Action with Id {" + actionId + "} does not exist"); } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetTagResource.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetTagResource.java index ef10efbad..76209a958 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetTagResource.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/rest/resource/TargetTagResource.java @@ -11,8 +11,6 @@ package org.eclipse.hawkbit.rest.resource; import java.util.List; import java.util.stream.Collectors; -import javax.persistence.EntityManager; - import org.eclipse.hawkbit.repository.TagFields; import org.eclipse.hawkbit.repository.TagManagement; import org.eclipse.hawkbit.repository.TargetManagement; @@ -21,6 +19,7 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTagAssigmentResult; import org.eclipse.hawkbit.repository.rsql.RSQLUtility; +import org.eclipse.hawkbit.rest.resource.api.TargetTagRestApi; import org.eclipse.hawkbit.rest.resource.model.tag.AssignedTargetRequestBody; import org.eclipse.hawkbit.rest.resource.model.tag.TagPagedList; import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut; @@ -36,13 +35,8 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; 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; /** @@ -50,10 +44,8 @@ import org.springframework.web.bind.annotation.RestController; * */ @RestController -@RequestMapping(RestConstants.TARGET_TAG_V1_REQUEST_MAPPING) -public class TargetTagResource { +public class TargetTagResource implements TargetTagRestApi { private static final Logger LOG = LoggerFactory.getLogger(TargetTagResource.class); - private static final String TARGET_TAG_TAGERTS_REQUEST_MAPPING = RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING; @Autowired private TagManagement tagManagement; @@ -61,34 +53,9 @@ public class TargetTagResource { @Autowired private TargetManagement targetManagement; - @Autowired - private EntityManager entityManager; - - /** - * Handles the GET request of retrieving all target tags. - * - * @param pagingOffsetParam - * the offset of list of target tags for pagination, might not be - * present in the rest request then default value will be applied - * @param pagingLimitParam - * the limit of the paged request, might not be present in the - * rest request then default value will be applied - * @param sortParam - * the sorting parameter in the request URL, syntax - * {@code field:direction, field:direction} - * @param rsqlParam - * the search parameter in the request URL, syntax - * {@code q=name==abc} - * @return a list of all target tags for a defined or default page request - * with status OK. The response is always paged. In any failure the - * 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) { + @Override + public ResponseEntity getTargetTags(final int pagingOffsetParam, final int pagingLimitParam, + final String sortParam, final String rsqlParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); @@ -98,11 +65,11 @@ public class TargetTagResource { final Slice findTargetsAll; final Long countTargetsAll; if (rsqlParam == null) { - findTargetsAll = tagManagement.findAllTargetTags(pageable); - countTargetsAll = tagManagement.countTargetTags(); + findTargetsAll = this.tagManagement.findAllTargetTags(pageable); + countTargetsAll = this.tagManagement.countTargetTags(); } else { - final Page findTargetPage = tagManagement + final Page findTargetPage = this.tagManagement .findAllTargetTags(RSQLUtility.parse(rsqlParam, TagFields.class), pageable); countTargetsAll = findTargetPage.getTotalElements(); findTargetsAll = findTargetPage; @@ -113,127 +80,57 @@ public class TargetTagResource { return new ResponseEntity<>(new TagPagedList(rest, countTargetsAll), HttpStatus.OK); } - /** - * Handles the GET request of retrieving a single target tag. - * - * @param targetTagId - * 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 final Long targetTagId) { + @Override + public ResponseEntity getTargetTag(final Long targetTagId) { final TargetTag tag = findTargetTagById(targetTagId); return new ResponseEntity<>(TagMapper.toResponse(tag), HttpStatus.OK); } - /** - * Handles the POST request of creating new target tag. The request body - * must always be a list of tags. - * - * @param tags - * the target tags to be created. - * @return In case all modules could successful created the ResponseEntity - * with status code 201 - Created. The Response Body are the created - * target tags but without ResponseBody. - */ - @RequestMapping(method = RequestMethod.POST, consumes = { "application/hal+json", - MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE }) + @Override public ResponseEntity createTargetTags(@RequestBody final List tags) { LOG.debug("creating {} target tags", tags.size()); - final List createdTargetTags = tagManagement + final List createdTargetTags = this.tagManagement .createTargetTags(TagMapper.mapTargeTagFromRequest(tags)); return new ResponseEntity<>(TagMapper.toResponse(createdTargetTags), HttpStatus.CREATED); } - /** - * - * Handles the PUT request of updating a single targetr tag. - * - * @param targetTagId - * the ID of the target tag - * @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 final Long targetTagId, - @RequestBody final TagRequestBodyPut restTargetTagRest) { + @Override + public ResponseEntity updateTagretTag(final Long targetTagId, final TagRequestBodyPut restTargetTagRest) { LOG.debug("update {} target tag", restTargetTagRest); final TargetTag targetTag = findTargetTagById(targetTagId); TagMapper.updateTag(restTargetTagRest, targetTag); - final TargetTag updateTargetTag = tagManagement.updateTargetTag(targetTag); + final TargetTag updateTargetTag = this.tagManagement.updateTargetTag(targetTag); LOG.debug("target tag updated"); return new ResponseEntity<>(TagMapper.toResponse(updateTargetTag), HttpStatus.OK); } - /** - * Handles the DELETE request for a single target tag. - * - * @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 final Long targetTagId) { + @Override + public ResponseEntity deleteTargetTag(final Long targetTagId) { LOG.debug("Delete {} target tag", targetTagId); final TargetTag targetTag = findTargetTagById(targetTagId); - tagManagement.deleteTargetTag(targetTag.getName()); + this.tagManagement.deleteTargetTag(targetTag.getName()); return new ResponseEntity<>(HttpStatus.OK); } - /** - * Handles the GET request of retrieving all assigned targets by the given - * tag id. - * - * @param targetTagId - * 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 = TARGET_TAG_TAGERTS_REQUEST_MAPPING) - public ResponseEntity getAssignedTargets(@PathVariable final Long targetTagId) { + @Override + public ResponseEntity getAssignedTargets(final Long targetTagId) { final TargetTag targetTag = findTargetTagById(targetTagId); return new ResponseEntity<>(TargetMapper.toResponseWithLinksAndPollStatus(targetTag.getAssignedToTargets()), HttpStatus.OK); } - /** - * Handles the POST request to toggle the assignment of targets by the given - * tag id. - * - * @param targetTagId - * the ID of the target tag to retrieve - * @param assignedTargetRequestBodies - * 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 = TARGET_TAG_TAGERTS_REQUEST_MAPPING + "/toggleTagAssignment") - public ResponseEntity toggleTagAssignment(@PathVariable final Long targetTagId, - @RequestBody final List assignedTargetRequestBodies) { + @Override + public ResponseEntity toggleTagAssignment(final Long targetTagId, + final List assignedTargetRequestBodies) { LOG.debug("Toggle Target assignment {} for target tag {}", assignedTargetRequestBodies.size(), targetTagId); final TargetTag targetTag = findTargetTagById(targetTagId); - final TargetTagAssigmentResult assigmentResult = targetManagement + final TargetTagAssigmentResult assigmentResult = this.targetManagement .toggleTagAssignment(findTargetControllerIds(assignedTargetRequestBodies), targetTag.getName()); final TargetTagAssigmentResultRest tagAssigmentResultRest = new TargetTagAssigmentResultRest(); @@ -242,71 +139,38 @@ public class TargetTagResource { return new ResponseEntity<>(tagAssigmentResultRest, HttpStatus.OK); } - /** - * Handles the POST request to assign targets to the given tag id. - * - * @param targetTagId - * the ID of the target tag to retrieve - * @param assignedTargetRequestBodies - * 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 = TARGET_TAG_TAGERTS_REQUEST_MAPPING) - public ResponseEntity assignTargets(@PathVariable final Long targetTagId, - @RequestBody final List assignedTargetRequestBodies) { + @Override + public ResponseEntity assignTargets(final Long targetTagId, + final List assignedTargetRequestBodies) { LOG.debug("Assign Targets {} for target tag {}", assignedTargetRequestBodies.size(), targetTagId); final TargetTag targetTag = findTargetTagById(targetTagId); - final List assignedTarget = targetManagement + final List assignedTarget = this.targetManagement .assignTag(findTargetControllerIds(assignedTargetRequestBodies), targetTag); return new ResponseEntity<>(TargetMapper.toResponseWithLinksAndPollStatus(assignedTarget), HttpStatus.OK); } - /** - * Handles the DELETE request to unassign all targets from the given tag id. - * - * @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 = TARGET_TAG_TAGERTS_REQUEST_MAPPING) - public ResponseEntity unassignTargets(@PathVariable final Long targetTagId) { + @Override + public ResponseEntity unassignTargets(final Long targetTagId) { LOG.debug("Unassign all Targets for target tag {}", targetTagId); final TargetTag targetTag = findTargetTagById(targetTagId); if (targetTag.getAssignedToTargets() == null) { LOG.debug("No assigned targets found"); return new ResponseEntity<>(HttpStatus.OK); } - targetManagement.unAssignAllTargetsByTag(targetTag); + this.targetManagement.unAssignAllTargetsByTag(targetTag); return new ResponseEntity<>(HttpStatus.OK); } - /** - * Handles the DELETE request to unassign one target from the given tag id. - * - * @param targetTagId - * the ID of the target tag - * @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 = TARGET_TAG_TAGERTS_REQUEST_MAPPING + "/{controllerId}") - public ResponseEntity unassignTarget(@PathVariable final Long targetTagId, - @PathVariable final String controllerId) { + @Override + public ResponseEntity unassignTarget(final Long targetTagId, final String controllerId) { LOG.debug("Unassign target {} for target tag {}", controllerId, targetTagId); final TargetTag targetTag = findTargetTagById(targetTagId); - targetManagement.unAssignTag(controllerId, targetTag); + this.targetManagement.unAssignTag(controllerId, targetTag); return new ResponseEntity<>(HttpStatus.OK); } private TargetTag findTargetTagById(final Long targetTagId) { - final TargetTag tag = tagManagement.findTargetTagById(targetTagId); + final TargetTag tag = this.tagManagement.findTargetTagById(targetTagId); if (tag == null) { throw new EntityNotFoundException("Target Tag with Id {" + targetTagId + "} does not exist"); } diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/ArtifactDownloadTest.java b/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/ArtifactDownloadTest.java index a87ce748a..2db088e64 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/ArtifactDownloadTest.java +++ b/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/ArtifactDownloadTest.java @@ -57,9 +57,6 @@ import ru.yandex.qatools.allure.annotations.Stories; /** * Test artifact downloads from the controller. * - * - * - * */ @ActiveProfiles({ "im", "test" }) @@ -285,7 +282,8 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { .andExpect(header().string("Content-Disposition", "attachment;filename=" + artifact.getFilename())) .andReturn(); - assertTrue(Arrays.equals(result.getResponse().getContentAsByteArray(), random)); + assertTrue("The same file that was uploaded is expected when downloaded", + Arrays.equals(result.getResponse().getContentAsByteArray(), random)); // download complete assertThat(downLoadProgress).isEqualTo(10); @@ -393,7 +391,8 @@ public class ArtifactDownloadTest extends AbstractIntegrationTestWithMongoDB { .andExpect(header().longValue("Last-Modified", artifact.getCreatedAt())) .andExpect(header().string("Content-Disposition", "attachment;filename=file1")).andReturn(); - assertTrue(Arrays.equals(result.getResponse().getContentAsByteArray(), random)); + assertTrue("The same file that was uploaded is expected when downloaded", + Arrays.equals(result.getResponse().getContentAsByteArray(), random)); // one (update) action assertThat(actionRepository.findByTargetAndDistributionSet(pageReq, target, ds).getContent()).hasSize(1); diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SortUtilityTest.java b/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SortUtilityTest.java index 7ca7814b2..d915c4e9e 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SortUtilityTest.java +++ b/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/SortUtilityTest.java @@ -8,7 +8,8 @@ */ package org.eclipse.hawkbit.rest.resource; -import static org.junit.Assert.assertEquals; +import static org.fest.assertions.api.Assertions.assertThat; +import static org.junit.Assert.fail; import java.util.List; @@ -16,9 +17,15 @@ import org.eclipse.hawkbit.repository.TargetFields; import org.junit.Test; import org.springframework.data.domain.Sort.Order; +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("Sorting parameter") public class SortUtilityTest { private static final String SORT_PARAM_1 = "NAME:ASC"; private static final String SORT_PARAM_2 = "NAME:ASC, DESCRIPTION:DESC"; @@ -29,36 +36,55 @@ public class SortUtilityTest { private static final String WRONG_FIELD_PARAM = "ASDF:ASC"; @Test + @Description("Ascending sorting based on name.") public void parseSortParam1() { - final List parse = SortUtility.parse(TargetFields.class, SORT_PARAM_1); - assertEquals(1, parse.size()); + assertThat(1).as("Count of parsing parameter").isEqualTo(parse.size()); } @Test + @Description("Ascending sorting based on name and descending sorting based on description.") public void parseSortParam2() { final List parse = SortUtility.parse(TargetFields.class, SORT_PARAM_2); - assertEquals(2, parse.size()); - } - - @Test(expected = SortParameterSyntaxErrorException.class) - public void parseWrongSyntaxParam() { - SortUtility.parse(TargetFields.class, SYNTAX_FAILURE_SORT_PARAM); + assertThat(2).as("Count of parsing parameter").isEqualTo(parse.size()); } @Test + @Description("Sorting with wrong syntax leads to SortParameterSyntaxErrorException.") + public void parseWrongSyntaxParam() { + try { + SortUtility.parse(TargetFields.class, SYNTAX_FAILURE_SORT_PARAM); + fail("SortParameterSyntaxErrorException expected because of wrong syntax"); + } catch (final SortParameterSyntaxErrorException e) { + } + } + + @Test + @Description("Sorting based on name with case sensitive is possible.") public void parsingIsNotCaseSensitive() { SortUtility.parse(TargetFields.class, CASE_INSENSITIVE_DIRECTION_PARAM); SortUtility.parse(TargetFields.class, CASE_INSENSITIVE_DIRECTION_PARAM_1); } - @Test(expected = SortParameterUnsupportedDirectionException.class) + @Test + @Description("Sorting with unknown direction order leads to SortParameterUnsupportedDirectionException.") public void parseWrongDirectionParam() { - SortUtility.parse(TargetFields.class, WRONG_DIRECTION_PARAM); + try { + SortUtility.parse(TargetFields.class, WRONG_DIRECTION_PARAM); + fail("SortParameterUnsupportedDirectionException expected because of unknown direction order"); + } catch (final SortParameterUnsupportedDirectionException e) { + } + } - @Test(expected = SortParameterUnsupportedFieldException.class) + @Test + @Description("Sorting with unknown field leads to SortParameterUnsupportedFieldException.") public void parseWrongFieldParam() { - SortUtility.parse(TargetFields.class, WRONG_FIELD_PARAM); + try { + SortUtility.parse(TargetFields.class, WRONG_FIELD_PARAM); + fail("SortParameterUnsupportedFieldException expected because of unknown field"); + } catch (final SortParameterUnsupportedFieldException e) { + } + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitUI.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitUI.java index b8e5545f3..d352211f6 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitUI.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitUI.java @@ -75,7 +75,7 @@ public class HawkbitUI extends DefaultHawkbitUI implements DetachListener { private SpringViewProvider viewProvider; @Autowired - private ApplicationContext context; + private transient ApplicationContext context; @Autowired private I18N i18n; @@ -89,13 +89,13 @@ public class HawkbitUI extends DefaultHawkbitUI implements DetachListener { private ErrorView errorview; @Autowired - protected EventBus.SessionEventBus eventBus; + protected transient EventBus.SessionEventBus eventBus; /** * An {@link com.google.common.eventbus.EventBus} subscriber which * subscribes {@link EntityEvent} from the repository to dispatch these * events to the UI {@link SessionEventBus}. - * + * * @param event * the entity event which has been published from the repository */ @@ -103,21 +103,28 @@ public class HawkbitUI extends DefaultHawkbitUI implements DetachListener { @AllowConcurrentEvents public void dispatch(final org.eclipse.hawkbit.eventbus.event.Event event) { final VaadinSession session = getSession(); - if (session != null && session.getState() == State.OPEN) { - final WrappedSession wrappedSession = session.getSession(); - if (wrappedSession != null) { - final SecurityContext userContext = (SecurityContext) wrappedSession - .getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); - if (eventSecurityCheck(userContext, event)) { - final SecurityContext oldContext = SecurityContextHolder.getContext(); - try { - access(new DispatcherRunnable(eventBus, session, userContext, event)); - } finally { - SecurityContextHolder.setContext(oldContext); - } - } - } + if (session == null || session.getState() != State.OPEN) { + return; } + + final WrappedSession wrappedSession = session.getSession(); + if (wrappedSession == null) { + return; + } + + final SecurityContext userContext = (SecurityContext) wrappedSession + .getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); + if (!eventSecurityCheck(userContext, event)) { + return; + } + + final SecurityContext oldContext = SecurityContextHolder.getContext(); + try { + access(new DispatcherRunnable(eventBus, session, userContext, event)); + } finally { + SecurityContextHolder.setContext(oldContext); + } + } protected boolean eventSecurityCheck(final SecurityContext userContext, @@ -134,7 +141,7 @@ public class HawkbitUI extends DefaultHawkbitUI implements DetachListener { /* * (non-Javadoc) - * + * * @see * com.vaadin.server.ClientConnector.DetachListener#detach(com.vaadin.server * .ClientConnector. DetachEvent) @@ -225,7 +232,7 @@ public class HawkbitUI extends DefaultHawkbitUI implements DetachListener { /** * Get Specific Locale. - * + * * @param availableLocalesInApp * as set * @return String as preferred locale 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 841256da4..eb8ed75e1 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 @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.ui.artifacts.footer; +import java.util.HashSet; import java.util.Set; import javax.annotation.PostConstruct; @@ -21,6 +22,7 @@ import org.eclipse.hawkbit.ui.common.footer.AbstractDeleteActionsLayout; import org.eclipse.hawkbit.ui.management.event.DragEvent; import org.eclipse.hawkbit.ui.utils.I18N; import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.UINotification; import org.springframework.beans.factory.annotation.Autowired; @@ -36,6 +38,7 @@ import com.vaadin.ui.Component; import com.vaadin.ui.Label; import com.vaadin.ui.Table; import com.vaadin.ui.UI; +import com.vaadin.ui.Table.TableTransferable; /** * Upload view footer layout implementation. @@ -196,7 +199,7 @@ public class SMDeleteActionsLayout extends AbstractDeleteActionsLayout { final Component sourceComponent = event.getTransferable().getSourceComponent(); if (sourceComponent instanceof Table) { final Table sourceTable = (Table) event.getTransferable().getSourceComponent(); - addToDeleteList(sourceTable); + addToDeleteList(sourceTable,(TableTransferable) event.getTransferable()); updateSWActionCount(); } if (sourceComponent.getId().startsWith(SPUIComponetIdProvider.UPLOAD_TYPE_BUTTON_PREFIX)) { @@ -220,16 +223,23 @@ public class SMDeleteActionsLayout extends AbstractDeleteActionsLayout { private void deleteSWModuleType(final String swModuleTypeName) { artifactUploadState.getSelectedDeleteSWModuleTypes().add(swModuleTypeName); } - - private void addToDeleteList(final Table sourceTable) { - final Set swModuleIds = (Set) sourceTable.getValue(); - swModuleIds.forEach(id -> { + + private void addToDeleteList(final Table sourceTable, final TableTransferable transferable) { + @SuppressWarnings("unchecked") + final Set swModuleSelected = (Set) sourceTable.getValue(); + final Set swModuleIdNameSet = new HashSet(); + if (!swModuleSelected.contains(transferable.getData(SPUIDefinitions.ITEMID))) { + swModuleIdNameSet.add((Long) transferable.getData(SPUIDefinitions.ITEMID)); + } else { + swModuleIdNameSet.addAll(swModuleSelected); + } + swModuleIdNameSet.forEach(id -> { final String swModuleName = (String) sourceTable.getContainerDataSource().getItem(id) .getItemProperty(SPUILabelDefinitions.NAME_VERSION).getValue(); artifactUploadState.getDeleteSofwareModules().put(id, swModuleName); }); } - + /** * Update the software module delete count. */ 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 537a76a70..49e9ab59f 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 @@ -44,9 +44,9 @@ import com.vaadin.ui.themes.ValoTheme; /** * Abstract layout of confirm actions window. - * * - * + * + * */ @SpringComponent @ViewScope @@ -84,13 +84,13 @@ public class UploadViewConfirmationWindowLayout extends AbstractConfirmationWind /* * (non-Javadoc) - * + * * @see org.eclipse.hawkbit.server.ui.common.confirmwindow.layout. * AbstractConfirmationWindowLayout# getConfimrationTabs() */ @Override protected Map getConfimrationTabs() { - final Map tabs = new HashMap(); + final Map tabs = new HashMap<>(); if (!artifactUploadState.getDeleteSofwareModules().isEmpty()) { tabs.put(i18n.get("caption.delete.swmodule.accordion.tab"), createSMDeleteConfirmationTab()); } @@ -145,7 +145,7 @@ public class UploadViewConfirmationWindowLayout extends AbstractConfirmationWind /** * Get SWModule table container. - * + * * @return IndexedContainer */ @SuppressWarnings("unchecked") @@ -153,9 +153,8 @@ public class UploadViewConfirmationWindowLayout extends AbstractConfirmationWind final IndexedContainer swcontactContainer = new IndexedContainer(); swcontactContainer.addContainerProperty("SWModuleId", String.class, ""); swcontactContainer.addContainerProperty(SW_MODULE_NAME_MSG, String.class, ""); - Item item = null; for (final Long swModuleID : artifactUploadState.getDeleteSofwareModules().keySet()) { - item = swcontactContainer.addItem(swModuleID); + final Item item = swcontactContainer.addItem(swModuleID); item.getItemProperty("SWModuleId").setValue(swModuleID.toString()); item.getItemProperty(SW_MODULE_NAME_MSG) .setValue(artifactUploadState.getDeleteSofwareModules().get(swModuleID)); @@ -197,7 +196,7 @@ public class UploadViewConfirmationWindowLayout extends AbstractConfirmationWind for (final CustomFile customFile : artifactUploadState.getFileSelected()) { final String swNameVersion = HawkbitCommonUtil.getFormattedNameVersion( customFile.getBaseSoftwareModuleName(), customFile.getBaseSoftwareModuleVersion()); - if (HawkbitCommonUtil.bothSame(deleteSoftwareNameVersion, swNameVersion)) { + if (deleteSoftwareNameVersion != null && deleteSoftwareNameVersion.equals(swNameVersion)) { tobeRemoved.add(customFile); } } 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 d653bb371..62a09c83b 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 @@ -38,13 +38,13 @@ public class ArtifactUploadState implements Serializable { private final Map deleteSofwareModules = new HashMap<>(); - private final Set fileSelected = new HashSet(); + private final Set fileSelected = new HashSet<>(); private Long selectedBaseSwModuleId; private SoftwareModule selectedBaseSoftwareModule; - private final Map baseSwModuleList = new HashMap(); + private final Map baseSwModuleList = new HashMap<>(); private Set selectedSoftwareModules = Collections.emptySet(); @@ -60,7 +60,7 @@ public class ArtifactUploadState implements Serializable { /** * Set software. - * + * * @return */ public SoftwareModuleFilters getSoftwareModuleFilters() { @@ -85,7 +85,7 @@ public class ArtifactUploadState implements Serializable { * @return the selectedBaseSwModuleId */ public Optional getSelectedBaseSwModuleId() { - return this.selectedBaseSwModuleId != null ? Optional.of(this.selectedBaseSwModuleId) : Optional.empty(); + return selectedBaseSwModuleId != null ? Optional.of(selectedBaseSwModuleId) : Optional.empty(); } /** @@ -100,8 +100,7 @@ public class ArtifactUploadState implements Serializable { * @return the selectedBaseSoftwareModule */ public Optional getSelectedBaseSoftwareModule() { - return this.selectedBaseSoftwareModule == null ? Optional.empty() - : Optional.of(this.selectedBaseSoftwareModule); + return selectedBaseSoftwareModule == null ? Optional.empty() : Optional.of(selectedBaseSoftwareModule); } /** diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/CustomFile.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/CustomFile.java index ff350511a..3dbbcc7db 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/CustomFile.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/CustomFile.java @@ -10,8 +10,6 @@ package org.eclipse.hawkbit.ui.artifacts.state; import java.io.Serializable; -import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; - /** * Custom file to hold details of uploaded file. * @@ -168,36 +166,50 @@ public class CustomFile implements Serializable { return failureReason; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ @Override - public int hashCode() { // NOSONAR - as this is generated + public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + (fileName == null ? 0 : fileName.hashCode()); + result = prime * result + ((baseSoftwareModuleName == null) ? 0 : baseSoftwareModuleName.hashCode()); + result = prime * result + ((baseSoftwareModuleVersion == null) ? 0 : baseSoftwareModuleVersion.hashCode()); + result = prime * result + ((fileName == null) ? 0 : fileName.hashCode()); return result; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } - if (!(obj instanceof CustomFile)) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { return false; } final CustomFile other = (CustomFile) obj; - return HawkbitCommonUtil.bothSame(fileName, other.fileName) - && HawkbitCommonUtil.bothSame(baseSoftwareModuleName, other.baseSoftwareModuleName) - && HawkbitCommonUtil.bothSame(baseSoftwareModuleVersion, other.baseSoftwareModuleVersion); + if (baseSoftwareModuleName == null) { + if (other.baseSoftwareModuleName != null) { + return false; + } + } else if (!baseSoftwareModuleName.equals(other.baseSoftwareModuleName)) { + return false; + } + if (baseSoftwareModuleVersion == null) { + if (other.baseSoftwareModuleVersion != null) { + return false; + } + } else if (!baseSoftwareModuleVersion.equals(other.baseSoftwareModuleVersion)) { + return false; + } + 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/common/filterlayout/AbstractFilterSingleButtonClick.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterSingleButtonClick.java index ccfbc922c..03b74b08d 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterSingleButtonClick.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterSingleButtonClick.java @@ -8,8 +8,6 @@ */ package org.eclipse.hawkbit.ui.common.filterlayout; -import java.util.Optional; - import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; import com.vaadin.ui.Button; @@ -17,20 +15,20 @@ import com.vaadin.ui.Button.ClickEvent; /** * Abstract Single button click behaviour of filter buttons layout. - * * * - * + * + * */ public abstract class AbstractFilterSingleButtonClick extends AbstractFilterButtonClickBehaviour { private static final long serialVersionUID = 478874092615793581L; - private Optional