From cdcde9cdcdc1d3d0712bc9bb73d7e899f01762e4 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Mon, 4 May 2026 14:26:11 +0200 Subject: [PATCH 01/18] hawkBit integration as extension --- hawkbit/build.gradle | 87 +++++ .../FirmwareDistributionSetResourceImpl.java | 107 ++++++ ...rmwareDistributionSetTypeResourceImpl.java | 93 +++++ .../manager/firmware/FirmwareService.java | 357 ++++++++++++++++++ .../FirmwareSoftwareModuleResourceImpl.java | 119 ++++++ ...irmwareSoftwareModuleTypeResourceImpl.java | 67 ++++ .../firmware/FirmwareTargetResourceImpl.java | 96 +++++ .../hawkbit/HawkbitArtifactUploadClient.java | 91 +++++ .../manager/hawkbit/HawkbitBasicAuth.java | 15 + .../HawkbitDistributionSetTypesResource.java | 54 +++ .../HawkbitDistributionSetsResource.java | 49 +++ .../HawkbitSoftwareModuleTypesResource.java | 39 ++ .../HawkbitSoftwareModulesResource.java | 46 +++ .../hawkbit/HawkbitTargetsResource.java | 67 ++++ .../model/firmware/FirmwareAction.java | 157 ++++++++ .../model/firmware/FirmwareActionLinks.java | 22 ++ .../model/firmware/FirmwareActions.java | 44 +++ .../model/firmware/FirmwareArtifact.java | 64 ++++ .../model/firmware/FirmwareArtifactLinks.java | 32 ++ .../model/firmware/FirmwareArtifacts.java | 44 +++ .../firmware/FirmwareAssignedAction.java | 22 ++ .../firmware/FirmwareDistributionSet.java | 134 +++++++ .../FirmwareDistributionSetAssignment.java | 84 +++++ ...rmwareDistributionSetAssignmentResult.java | 54 +++ .../FirmwareDistributionSetResource.java | 57 +++ .../firmware/FirmwareDistributionSetType.java | 103 +++++ .../FirmwareDistributionSetTypeResource.java | 67 ++++ .../FirmwareDistributionSetTypes.java | 44 +++ .../firmware/FirmwareDistributionSets.java | 44 +++ .../hawkbit/model/firmware/FirmwareLink.java | 32 ++ .../firmware/FirmwareMaintenanceWindow.java | 42 +++ .../model/firmware/FirmwareMetaItemType.java | 20 + .../model/firmware/FirmwarePollStatus.java | 42 +++ .../firmware/FirmwareSoftwareModule.java | 122 ++++++ .../FirmwareSoftwareModuleResource.java | 69 ++++ .../firmware/FirmwareSoftwareModuleType.java | 92 +++++ .../FirmwareSoftwareModuleTypeAssignment.java | 22 ++ .../FirmwareSoftwareModuleTypeResource.java | 49 +++ .../firmware/FirmwareSoftwareModuleTypes.java | 44 +++ .../firmware/FirmwareSoftwareModules.java | 44 +++ .../model/firmware/FirmwareTarget.java | 158 ++++++++ .../firmware/FirmwareTargetAssignment.java | 72 ++++ .../firmware/FirmwareTargetResource.java | 71 ++++ .../model/firmware/FirmwareTargets.java | 44 +++ .../org.openremote.model.ContainerService | 1 + 45 files changed, 3183 insertions(+) create mode 100644 hawkbit/build.gradle create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitBasicAuth.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAssignedAction.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java create mode 100644 hawkbit/src/main/resources/META-INF/services/org.openremote.model.ContainerService diff --git a/hawkbit/build.gradle b/hawkbit/build.gradle new file mode 100644 index 0000000..7a4b24c --- /dev/null +++ b/hawkbit/build.gradle @@ -0,0 +1,87 @@ +apply plugin: "groovy" +apply plugin: "java-library" +apply plugin: "maven-publish" +apply plugin: "signing" + +base { + archivesName = "openremote-${project.name}-extension" +} + +dependencies { + api "io.openremote:openremote-manager:$openremoteVersion" + api "io.openremote:openremote-model:$openremoteVersion" + + api "org.jboss.resteasy:resteasy-client-api:$resteasyVersion" + api "org.jboss.resteasy:resteasy-jaxb-provider:$resteasyVersion" + + testImplementation "io.openremote:openremote-test:$openremoteVersion" +} + +jar { + from sourceSets.main.allJava +} + +javadoc { + failOnError = false +} + +java { + withJavadocJar() + withSourcesJar() +} + +publishing { + publications { + maven(MavenPublication) { + group = "io.openremote.extension" + artifactId = "openremote-${project.name}-extension" + from components.java + pom { + name = 'OpenRemote hawkBit extension' + description = 'Adds the hawkBit extension' + url = 'https://github.com/openremote/extensions' + licenses { + license { + name = 'GNU Affero General Public License v3.0' + url = 'https://www.gnu.org/licenses/agpl-3.0.en.html' + } + } + developers { + developer { + id = 'developers' + name = 'Developers' + email = 'developers@openremote.io' + organization = 'OpenRemote' + organizationUrl = 'https://openremote.io' + } + } + scm { + connection = 'scm:git:git://github.com/openremote/extensions.git' + developerConnection = 'scm:git:ssh://github.com:openremote/extensions.git' + url = 'https://github.com/openremote/extensions/tree/main' + } + } + } + } + + repositories { + maven { + if (!version.endsWith('-LOCAL')) { + credentials { + username = findProperty("publishUsername") + password = findProperty("publishPassword") + } + } + url = version.endsWith('-LOCAL') ? layout.buildDirectory.dir('repo') : version.endsWith('-SNAPSHOT') ? findProperty("snapshotsRepoUrl") : findProperty("releasesRepoUrl") + } + } +} + +signing { + def signingKey = findProperty("signingKey") + def signingPassword = findProperty("signingPassword") + if (signingKey && signingPassword) { + useInMemoryPgpKeys(signingKey, signingPassword) + sign publishing.publications.maven + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java new file mode 100644 index 0000000..cc8c59e --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java @@ -0,0 +1,107 @@ +package org.openremote.extension.hawkbit.manager.firmware; + +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import org.openremote.container.timer.TimerService; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.manager.web.ManagerWebResource; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetAssignment; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetAssignmentResult; +import org.openremote.model.http.RequestParams; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetResource; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSets; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetAssignment; + +import java.util.List; + +public class FirmwareDistributionSetResourceImpl extends ManagerWebResource + implements FirmwareDistributionSetResource { + + protected final FirmwareService firmwareService; + + public FirmwareDistributionSetResourceImpl(TimerService timerService, ManagerIdentityService identityService, + FirmwareService firmwareService) { + super(timerService, identityService); + this.firmwareService = firmwareService; + } + + @Override + public FirmwareDistributionSet createDistributionSet(RequestParams requestParams, + FirmwareDistributionSet distributionSet) { + try { + FirmwareDistributionSet[] created = + firmwareService.distributionSetsResource.create(new FirmwareDistributionSet[] { distributionSet }); + return created != null && created.length > 0 ? created[0] : null; + } catch (Exception e) { + throw new WebApplicationException("Failed to create firmware distribution set", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareDistributionSetAssignmentResult assignDistributionSet(RequestParams requestParams, Long id, + FirmwareDistributionSetAssignment assignment) { + try { + if (assignment == null || assignment.getTargets() == null || assignment.getTargets().isEmpty()) { + throw new WebApplicationException("Assignment requires at least one target", Response.Status.BAD_REQUEST); + } + + List targets = assignment.getTargets().stream() + .map(target -> new FirmwareTargetAssignment() + .setId(target.getId()) + .setForcetime(target.getForcetime() != null ? target.getForcetime() : assignment.getForcetime()) + .setWeight(target.getWeight() != null ? target.getWeight() : assignment.getWeight()) + .setConfirmationRequired(target.getConfirmationRequired() != null + ? target.getConfirmationRequired() + : assignment.getConfirmationRequired()) + .setType(target.getType() != null ? target.getType() : assignment.getType()) + .setMaintenanceWindow(target.getMaintenanceWindow() != null + ? target.getMaintenanceWindow() + : assignment.getMaintenanceWindow())) + .toList(); + + return firmwareService.distributionSetsResource.assignTargets(id, assignment.getOffline(), + targets.toArray(FirmwareTargetAssignment[]::new)); + } catch (WebApplicationException e) { + throw e; + } catch (Exception e) { + throw new WebApplicationException("Failed to assign firmware distribution set '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareDistributionSets getDistributionSets(RequestParams requestParams, Integer offset, Integer limit) { + try { + return firmwareService.distributionSetsResource.getDistributionSets(offset, limit); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware distribution sets", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareDistributionSet getDistributionSet(RequestParams requestParams, Long id) { + try { + return firmwareService.distributionSetsResource.get(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware distribution set '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @DELETE + @Path("{id}") + public void deleteDistributionSet(RequestParams requestParams, @PathParam("id") Long id) { + try { + firmwareService.distributionSetsResource.delete(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to delete firmware distribution set '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java new file mode 100644 index 0000000..af1e19f --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java @@ -0,0 +1,93 @@ +package org.openremote.extension.hawkbit.manager.firmware; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import org.openremote.container.timer.TimerService; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.manager.web.ManagerWebResource; +import org.openremote.model.http.RequestParams; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetType; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypeResource; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypes; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleType; + +public class FirmwareDistributionSetTypeResourceImpl extends ManagerWebResource + implements FirmwareDistributionSetTypeResource { + + protected final FirmwareService firmwareService; + + public FirmwareDistributionSetTypeResourceImpl(TimerService timerService, + ManagerIdentityService identityService, + FirmwareService firmwareService) { + super(timerService, identityService); + this.firmwareService = firmwareService; + } + + @Override + public FirmwareDistributionSetType createDistributionSetType(RequestParams requestParams, + FirmwareDistributionSetType distributionSetType) { + try { + FirmwareDistributionSetType[] created = firmwareService.distributionSetTypesResource.create( + new FirmwareDistributionSetType[] { distributionSetType }); + return created != null && created.length > 0 ? created[0] : null; + } catch (Exception e) { + throw new WebApplicationException("Failed to create firmware distribution set type", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareDistributionSetTypes getDistributionSetTypes(RequestParams requestParams, Integer offset, + Integer limit) { + try { + return firmwareService.distributionSetTypesResource.getDistributionSetTypes(offset, limit); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware distribution set types", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareDistributionSetType getDistributionSetType(RequestParams requestParams, Long id) { + try { + return firmwareService.distributionSetTypesResource.get(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware distribution set type '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareSoftwareModuleType[] getMandatoryModuleTypes(RequestParams requestParams, Long id, Integer offset, + Integer limit) { + try { + return firmwareService.distributionSetTypesResource.getMandatoryModuleTypes(id, offset, limit); + } catch (Exception e) { + throw new WebApplicationException( + "Failed to retrieve mandatory module types for firmware distribution set type '" + id + "'", + e, Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareSoftwareModuleType[] getOptionalModuleTypes(RequestParams requestParams, Long id, Integer offset, + Integer limit) { + try { + return firmwareService.distributionSetTypesResource.getOptionalModuleTypes(id, offset, limit); + } catch (Exception e) { + throw new WebApplicationException( + "Failed to retrieve optional module types for firmware distribution set type '" + id + "'", + e, Response.Status.BAD_GATEWAY); + } + } + + @Override + public void deleteDistributionSetType(RequestParams requestParams, Long id) { + try { + firmwareService.distributionSetTypesResource.delete(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to delete firmware distribution set type '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java new file mode 100644 index 0000000..a908caf --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java @@ -0,0 +1,357 @@ +/* + * Copyright 2021, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.manager.firmware; + +import static org.openremote.container.web.WebTargetBuilder.CONNECTION_POOL_SIZE; +import static org.openremote.container.web.WebTargetBuilder.CONNECTION_TIMEOUT_MILLISECONDS; +import static org.openremote.container.web.WebTargetBuilder.createClient; +import static org.openremote.model.syslog.SyslogCategory.API; +import static org.openremote.model.util.MapAccess.getString; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.core.HttpHeaders; +import org.jboss.resteasy.client.jaxrs.ResteasyClient; +import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; +import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; +import org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider; +import org.openremote.container.timer.TimerService; +import org.openremote.container.web.WebClient; +import org.openremote.container.web.WebTargetBuilder; +import org.openremote.manager.asset.AssetProcessingService; +import org.openremote.manager.event.ClientEventService; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitArtifactUploadClient; +import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitBasicAuth; +import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitDistributionSetsResource; +import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitDistributionSetTypesResource; +import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitSoftwareModulesResource; +import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitSoftwareModuleTypesResource; +import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitTargetsResource; +import org.openremote.manager.web.ManagerWebService; +import org.openremote.model.Container; +import org.openremote.model.ContainerService; +import org.openremote.model.asset.Asset; +import org.openremote.model.asset.AssetEvent; +import org.openremote.model.asset.AssetTypeInfo; +import org.openremote.model.attribute.AttributeEvent; +import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifact; +import org.openremote.extension.hawkbit.model.firmware.FirmwareMetaItemType; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTarget; +import org.openremote.model.syslog.SyslogCategory; +import org.openremote.model.util.TextUtil; +import org.openremote.model.util.ValueUtil; +import org.openremote.model.value.AttributeDescriptor; + +public class FirmwareService implements ContainerService { + + + public static final String HAWKBIT_REALM = "HAWKBIT_REALM"; + public static final String HAWKBIT_REALM_DEFAULT = "master"; + public static final String HAWKBIT_USERNAME = "HAWKBIT_USERNAME"; + public static final String HAWKBIT_USERNAME_DEFAULT = "hawkbit"; + public static final String HAWKBIT_PASSWORD = "HAWKBIT_PASSWORD"; + public static final String HAWKBIT_PASSWORD_DEFAULT = "hawkbit"; + + public static final String HAWKBIT_MANAGEMENT_API_URL = "HAWKBIT_MANAGEMENT_API_URL"; + public static final String HAWKBIT_MANAGEMENT_API_URL_DEFAULT = "http://localhost:8083/hawkbit/rest/v1"; + + protected static final Logger LOG = SyslogCategory.getLogger(API, FirmwareService.class); + + protected static ResteasyClient client; + + protected String hawkbitRealm; + protected ClientEventService clientEventService; + protected ManagerIdentityService identityService; + protected AssetProcessingService assetProcessingService; + protected ExecutorService executorService; + protected TimerService timerService; + protected HawkbitTargetsResource targetsResource; + protected HawkbitDistributionSetsResource distributionSetsResource; + protected HawkbitDistributionSetTypesResource distributionSetTypesResource; + protected HawkbitSoftwareModulesResource softwareModulesResource; + protected HawkbitSoftwareModuleTypesResource softwareModuleTypesResource; + protected HawkbitArtifactUploadClient artifactUploadClient; + + static { + client = createClient(org.openremote.container.Container.EXECUTOR, CONNECTION_POOL_SIZE, + CONNECTION_TIMEOUT_MILLISECONDS, resteasyClientBuilder -> { + WebClient.registerDefaults((ResteasyClientBuilderImpl) resteasyClientBuilder); + ResteasyJackson2Provider provider = new ResteasyJackson2Provider(); + provider.setMapper(ValueUtil.JSON); + resteasyClientBuilder.register(provider); + return resteasyClientBuilder; + }); + } + + @Override + public void init(Container container) throws Exception { + clientEventService = container.getService(ClientEventService.class); + assetProcessingService = container.getService(AssetProcessingService.class); + executorService = container.getExecutor(); + timerService = container.getService(TimerService.class); + identityService = container.getService(ManagerIdentityService.class); + + // API resources + container.getService(ManagerWebService.class).addApiSingleton( + new FirmwareTargetResourceImpl(timerService, identityService, this)); + container.getService(ManagerWebService.class).addApiSingleton( + new FirmwareDistributionSetResourceImpl(timerService, identityService, this)); + container.getService(ManagerWebService.class).addApiSingleton( + new FirmwareDistributionSetTypeResourceImpl(timerService, identityService, this)); + container.getService(ManagerWebService.class).addApiSingleton( + new FirmwareSoftwareModuleResourceImpl(timerService, identityService, this)); + container.getService(ManagerWebService.class).addApiSingleton( + new FirmwareSoftwareModuleTypeResourceImpl(timerService, identityService, this)); + } + + @Override + public void start(Container container) throws Exception { + String hawkbitURI = getString(container.getConfig(), HAWKBIT_MANAGEMENT_API_URL, + HAWKBIT_MANAGEMENT_API_URL_DEFAULT); + + if (TextUtil.isNullOrEmpty(hawkbitURI)) { + hawkbitURI = HAWKBIT_MANAGEMENT_API_URL_DEFAULT; + } + + if (HAWKBIT_MANAGEMENT_API_URL_DEFAULT.equals(hawkbitURI)) { + LOG.info(HAWKBIT_MANAGEMENT_API_URL + " not configured, using default=" + + HAWKBIT_MANAGEMENT_API_URL_DEFAULT); + } + + URI uri; + + try { + uri = new URI(hawkbitURI); + } catch (URISyntaxException e) { + LOG.log(Level.SEVERE, HAWKBIT_MANAGEMENT_API_URL + " value is not a valid URI", e); + throw e; + } + + String hawkbitUsername = getString(container.getConfig(), HAWKBIT_USERNAME, HAWKBIT_USERNAME_DEFAULT); + String hawkbitPassword = getString(container.getConfig(), HAWKBIT_PASSWORD, HAWKBIT_PASSWORD_DEFAULT); + + hawkbitRealm = getString(container.getConfig(), HAWKBIT_REALM, HAWKBIT_REALM_DEFAULT); + + LOG.info(HAWKBIT_MANAGEMENT_API_URL + "=" + uri); + + ResteasyWebTarget webTarget = new WebTargetBuilder(client, uri).build(); + webTarget.register((ClientRequestFilter) requestContext -> requestContext.getHeaders().putSingle( + HttpHeaders.AUTHORIZATION, + HawkbitBasicAuth.buildAuthorizationHeader(hawkbitUsername, hawkbitPassword))); + + // Set targets resource + targetsResource = webTarget.proxy(HawkbitTargetsResource.class); + distributionSetsResource = webTarget.proxy(HawkbitDistributionSetsResource.class); + distributionSetTypesResource = webTarget.proxy(HawkbitDistributionSetTypesResource.class); + softwareModulesResource = webTarget.proxy(HawkbitSoftwareModulesResource.class); + softwareModuleTypesResource = webTarget.proxy(HawkbitSoftwareModuleTypesResource.class); + + // Artifact upload uses raw multipart forwarding because Hawkbit expects + // multipart/form-data for this endpoint. + artifactUploadClient = new HawkbitArtifactUploadClient(uri, hawkbitUsername, hawkbitPassword); + + // Subscribe for asset events + clientEventService.addSubscription( + AssetEvent.class, + null, + this::onAssetChange); + + LOG.log(Level.INFO, + "Firmware Service started, connected hawkBit instance: " + uri + ", for realm: " + hawkbitRealm); + } + + @Override + public void stop(Container container) throws Exception { + + } + + public FirmwareArtifact uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream inputStream, + String originalFilename, String filename) + throws IOException, InterruptedException { + return artifactUploadClient.uploadSoftwareModuleArtifact(softwareModuleId, inputStream, + originalFilename, filename); + } + + private void onAssetChange(AssetEvent assetEvent) { + // Ignore events if they are not for the configured hawkBit realm + if (!Objects.equals(assetEvent.getRealm(), hawkbitRealm)) + { + return; + } + + // Submit the assetEvent to the executorService + executorService.submit(() -> handleAssetChange(assetEvent)); + } + + private void handleAssetChange(AssetEvent assetEvent) { + Asset asset = assetEvent.getAsset(); + + if (getFirmwareTargetInfoDescriptor(asset).isEmpty()) { + return; + } + + String controllerId = asset.getId(); + boolean shouldUpdateFirmwareTargetInfo = false; + + LOG.info("Processing hawkbit target sync cause=" + assetEvent.getCause() + + ", assetId=" + asset.getId() + ", assetType=" + asset.getType() + + ", controllerId=" + controllerId); + + switch (assetEvent.getCause()) { + case CREATE: + LOG.info("Creating hawkbit target for asset id=" + asset.getId()); + shouldUpdateFirmwareTargetInfo = createFirmwareTarget(buildFirmwareTarget(asset)); + break; + case UPDATE: + LOG.info("Checking hawkbit target for update asset id=" + asset.getId()); + try { + FirmwareTarget existingTarget = targetsResource.get(controllerId); + if (existingTarget != null) { + LOG.info("hawkbit target already exists so nothing to do id=" + controllerId); + shouldUpdateFirmwareTargetInfo = true; + break; + } + } catch (Exception e) { + LOG.log(Level.FINE, "Failed to load hawkbit target id=" + controllerId + + ", trying create instead", e); + } + + if (createFirmwareTarget(buildFirmwareTarget(asset))) { + LOG.info("hawkbit target missing for asset id=" + asset.getId() + ", creating it now"); + shouldUpdateFirmwareTargetInfo = true; + } + break; + case DELETE: + deleteFirmwareTarget(controllerId); + break; + default: + break; + } + + if (shouldUpdateFirmwareTargetInfo) { + updateFirmwareTargetInfo(assetEvent); + } + } + + @SuppressWarnings({ "rawtypes" }) + private Optional> getFirmwareTargetInfoDescriptor(Asset asset) { + Optional assetTypeInfo = ValueUtil.getAssetInfo(asset.getType()); + if (assetTypeInfo.isEmpty()) { + LOG.warning("Cannot resolve asset type info for asset type '" + asset.getType() + "'"); + return Optional.empty(); + } + + List> matchingDescriptors = assetTypeInfo.get().getAttributeDescriptors().values() + .stream() + .filter(attributeDescriptor -> attributeDescriptor.getMeta() != null + && attributeDescriptor.getMeta() + .get(FirmwareMetaItemType.FIRMWARE_TARGET) + .flatMap(metaItem -> metaItem.getValue(Boolean.class)) + .orElse(false)) + .toList(); + + if (matchingDescriptors.isEmpty()) { + return Optional.empty(); + } + + if (matchingDescriptors.size() > 1) { + LOG.warning("Asset type '" + asset.getType() + + "' has multiple attribute descriptors with meta item '" + + FirmwareMetaItemType.FIRMWARE_TARGET.getName() + "'"); + return Optional.empty(); + } + + return Optional.of((AttributeDescriptor) matchingDescriptors.getFirst()); + } + + private FirmwareTarget buildFirmwareTarget(Asset asset) { + String controllerId = asset.getId(); + String targetName = asset.getAssetType() + "-" + controllerId; + String targetDescription = "assetId=" + asset.getId() + "; realm=" + asset.getRealm(); + return new FirmwareTarget(controllerId, targetName, targetDescription); + } + + private boolean createFirmwareTarget(FirmwareTarget target) { + LOG.info("Creating hawkbit target id=" + target.getControllerId()); + try { + targetsResource.create(new FirmwareTarget[] { target }); + return true; + } catch (Exception e) { + LOG.log(Level.WARNING, "Failed to create hawkbit target id=" + target.getControllerId(), e); + return false; + } + } + + private boolean deleteFirmwareTarget(String controllerId) { + try { + targetsResource.delete(controllerId); + LOG.info("Deleted hawkbit target id=" + controllerId); + return true; + } catch (Exception e) { + LOG.log(Level.WARNING, "Failed to delete hawkbit target id=" + controllerId, e); + return false; + } + } + + private void updateFirmwareTargetInfo(AssetEvent assetEvent) { + Asset asset = assetEvent.getAsset(); + Optional> firmwareTargetInfoDescriptor = getFirmwareTargetInfoDescriptor(asset); + if (firmwareTargetInfoDescriptor.isEmpty()) { + return; + } + + String attributeName = firmwareTargetInfoDescriptor.get().getName(); + String controllerId = asset.getId(); + + switch (assetEvent.getCause()) { + case CREATE: + case UPDATE: + try { + FirmwareTarget firmwareTarget = targetsResource.get(controllerId); + Map firmwareTargetInfo = new LinkedHashMap<>(); + firmwareTargetInfo.put("controllerId", firmwareTarget.getControllerId()); + firmwareTargetInfo.put("securityToken", firmwareTarget.getSecurityToken()); + assetProcessingService.sendAttributeEvent( + new AttributeEvent( + asset.getId(), + attributeName, + ValueUtil.asJSON(firmwareTargetInfo).orElse(null)), + getClass().getSimpleName()); + LOG.info("Updated firmware target info attribute for asset id=" + asset.getId() + + ", controllerId=" + firmwareTarget.getControllerId()); + } catch (Exception e) { + LOG.log(Level.WARNING, "Failed to update firmware target info for asset id=" + asset.getId(), e); + } + break; + default: + break; + } + } + +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java new file mode 100644 index 0000000..196f267 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java @@ -0,0 +1,119 @@ +package org.openremote.extension.hawkbit.manager.firmware; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.openremote.container.timer.TimerService; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.manager.web.ManagerWebResource; +import org.openremote.model.http.RequestParams; +import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifact; +import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifacts; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModule; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleResource; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModules; + +import java.io.InputStream; +import java.util.List; + +public class FirmwareSoftwareModuleResourceImpl extends ManagerWebResource + implements FirmwareSoftwareModuleResource { + + protected final FirmwareService firmwareService; + + public FirmwareSoftwareModuleResourceImpl(TimerService timerService, ManagerIdentityService identityService, + FirmwareService firmwareService) { + super(timerService, identityService); + this.firmwareService = firmwareService; + } + + @Override + public FirmwareSoftwareModule createSoftwareModule(RequestParams requestParams, + FirmwareSoftwareModule softwareModule) { + try { + FirmwareSoftwareModule[] created = + firmwareService.softwareModulesResource.create(new FirmwareSoftwareModule[] { softwareModule }); + return created != null && created.length > 0 ? created[0] : null; + } catch (Exception e) { + throw new WebApplicationException("Failed to create firmware software module", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareSoftwareModules getSoftwareModules(RequestParams requestParams, Integer offset, Integer limit) { + try { + return firmwareService.softwareModulesResource.getSoftwareModules(offset, limit); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware software modules", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareSoftwareModule getSoftwareModule(RequestParams requestParams, Long id) { + try { + return firmwareService.softwareModulesResource.get(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware software module '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareArtifacts getSoftwareModuleArtifacts(RequestParams requestParams, Long id) { + try { + return firmwareService.softwareModulesResource.getArtifacts(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve artifacts for firmware software module '" + id + "'", + e, Response.Status.BAD_GATEWAY); + } + } + + @POST + @Path("{id}/artifacts") + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + public FirmwareArtifact uploadSoftwareModuleArtifact(RequestParams requestParams, + @PathParam("id") Long id, + @QueryParam("filename") String filename, + List parts) { + try { + EntityPart filePart = parts == null ? null : parts.stream() + .filter(part -> "file".equals(part.getName())) + .findFirst() + .orElse(null); + if (filePart == null) { + throw new WebApplicationException("Missing multipart field 'file'", Response.Status.BAD_REQUEST); + } + + String submittedFileName = filePart.getFileName().orElse(null); + InputStream inputStream = filePart.getContent(InputStream.class); + return firmwareService.uploadSoftwareModuleArtifact(id, inputStream, submittedFileName, filename); + } catch (WebApplicationException e) { + throw e; + } catch (Exception e) { + throw new WebApplicationException("Failed to upload artifact for firmware software module '" + id + "'", + e, Response.Status.BAD_GATEWAY); + } + } + + @DELETE + @Path("{id}") + public void deleteSoftwareModule(RequestParams requestParams, @PathParam("id") Long id) { + try { + firmwareService.softwareModulesResource.delete(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to delete firmware software module '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java new file mode 100644 index 0000000..93c3fe1 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java @@ -0,0 +1,67 @@ +package org.openremote.extension.hawkbit.manager.firmware; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import org.openremote.container.timer.TimerService; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.manager.web.ManagerWebResource; +import org.openremote.model.http.RequestParams; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleType; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypeResource; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypes; + +public class FirmwareSoftwareModuleTypeResourceImpl extends ManagerWebResource + implements FirmwareSoftwareModuleTypeResource { + + protected final FirmwareService firmwareService; + + public FirmwareSoftwareModuleTypeResourceImpl(TimerService timerService, ManagerIdentityService identityService, + FirmwareService firmwareService) { + super(timerService, identityService); + this.firmwareService = firmwareService; + } + + @Override + public FirmwareSoftwareModuleType createSoftwareModuleType(RequestParams requestParams, + FirmwareSoftwareModuleType softwareModuleType) { + try { + FirmwareSoftwareModuleType[] created = firmwareService.softwareModuleTypesResource.create( + new FirmwareSoftwareModuleType[] { softwareModuleType }); + return created != null && created.length > 0 ? created[0] : null; + } catch (Exception e) { + throw new WebApplicationException("Failed to create firmware software module type", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareSoftwareModuleTypes getSoftwareModuleTypes(RequestParams requestParams, Integer offset, + Integer limit) { + try { + return firmwareService.softwareModuleTypesResource.getSoftwareModuleTypes(offset, limit); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware software module types", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareSoftwareModuleType getSoftwareModuleType(RequestParams requestParams, Long id) { + try { + return firmwareService.softwareModuleTypesResource.get(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware software module type '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public void deleteSoftwareModuleType(RequestParams requestParams, Long id) { + try { + firmwareService.softwareModuleTypesResource.delete(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to delete firmware software module type '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java new file mode 100644 index 0000000..4cdab72 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java @@ -0,0 +1,96 @@ +package org.openremote.extension.hawkbit.manager.firmware; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import org.openremote.container.timer.TimerService; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.manager.web.ManagerWebResource; +import org.openremote.model.http.RequestParams; +import org.openremote.extension.hawkbit.model.firmware.FirmwareAction; +import org.openremote.extension.hawkbit.model.firmware.FirmwareActions; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTarget; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetResource; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargets; + +public class FirmwareTargetResourceImpl extends ManagerWebResource implements FirmwareTargetResource { + + protected final FirmwareService firmwareService; + + public FirmwareTargetResourceImpl(TimerService timerService, ManagerIdentityService identityService, + FirmwareService firmwareService) { + super(timerService, identityService); + this.firmwareService = firmwareService; + } + + @Override + public FirmwareTargets getTargets(RequestParams requestParams, Integer offset, Integer limit) { + try { + return firmwareService.targetsResource.getTargets(offset, limit); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware targets", e, Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareTarget getTarget(RequestParams requestParams, String id) { + try { + return firmwareService.targetsResource.get(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware target '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareDistributionSet getAssignedDs(RequestParams requestParams, String id) { + try { + return firmwareService.targetsResource.getAssignedDs(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve assigned DS for firmware target '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareDistributionSet getInstalledDs(RequestParams requestParams, String id) { + try { + return firmwareService.targetsResource.getInstalledDs(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve installed DS for firmware target '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareActions getActions(RequestParams requestParams, String id, Integer offset, Integer limit) { + try { + return firmwareService.targetsResource.getActions(id, offset, limit); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve actions for firmware target '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareAction getAction(RequestParams requestParams, String id, Long actionId) { + try { + return firmwareService.targetsResource.getAction(id, actionId); + } catch (Exception e) { + throw new WebApplicationException( + "Failed to retrieve action '" + actionId + "' for firmware target '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public void cancelAction(RequestParams requestParams, String id, Long actionId, Boolean force) { + try { + firmwareService.targetsResource.cancelAction(id, actionId, force); + } catch (Exception e) { + throw new WebApplicationException( + "Failed to cancel action '" + actionId + "' for firmware target '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java new file mode 100644 index 0000000..38d1fa1 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java @@ -0,0 +1,91 @@ +package org.openremote.extension.hawkbit.manager.hawkbit; + +import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifact; +import org.openremote.model.util.TextUtil; +import org.openremote.model.util.ValueUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +public class HawkbitArtifactUploadClient { + + protected final URI hawkbitManagementUri; + protected final String hawkbitUsername; + protected final String hawkbitPassword; + + public HawkbitArtifactUploadClient(URI hawkbitManagementUri, String hawkbitUsername, String hawkbitPassword) { + this.hawkbitManagementUri = hawkbitManagementUri; + this.hawkbitUsername = hawkbitUsername; + this.hawkbitPassword = hawkbitPassword; + } + + public FirmwareArtifact uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream inputStream, + String originalFilename, String filename) + throws IOException, InterruptedException { + String effectiveFilename = TextUtil.isNullOrEmpty(filename) ? originalFilename : filename; + String boundary = "----OpenRemoteBoundary" + UUID.randomUUID(); + byte[] payload = buildMultipartPayload(boundary, inputStream.readAllBytes(), effectiveFilename); + + HttpRequest request = HttpRequest.newBuilder( + buildArtifactUploadUri(softwareModuleId, effectiveFilename)) + .header("Authorization", HawkbitBasicAuth.buildAuthorizationHeader(hawkbitUsername, hawkbitPassword)) + .header("Accept", "application/hal+json") + .header("Content-Type", "multipart/form-data; boundary=" + boundary) + .POST(HttpRequest.BodyPublishers.ofByteArray(payload)) + .build(); + + HttpResponse response = HttpClient.newHttpClient() + .send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + + if (response.statusCode() < 200 || response.statusCode() >= 300) { + throw new IOException("Artifact upload failed with status " + response.statusCode() + ": " + response.body()); + } + + return ValueUtil.JSON.readValue(response.body(), FirmwareArtifact.class); + } + + protected URI buildArtifactUploadUri(Long softwareModuleId, String filename) { + StringBuilder uriBuilder = new StringBuilder(hawkbitManagementUri.toString()) + .append("/softwaremodules/") + .append(softwareModuleId) + .append("/artifacts"); + + appendQueryParam(uriBuilder, "filename", filename, true); + return URI.create(uriBuilder.toString()); + } + + protected boolean appendQueryParam(StringBuilder uriBuilder, String name, String value, boolean first) { + if (TextUtil.isNullOrEmpty(value)) { + return first; + } + + uriBuilder.append(first ? '?' : '&') + .append(name) + .append('=') + .append(URLEncoder.encode(value, StandardCharsets.UTF_8)); + return false; + } + + protected byte[] buildMultipartPayload(String boundary, byte[] fileBytes, String filename) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream.write(("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8)); + outputStream.write(("Content-Disposition: form-data; name=\"file\"; filename=\"" + escapeQuoted(filename) + + "\"\r\n").getBytes(StandardCharsets.UTF_8)); + outputStream.write("Content-Type: application/octet-stream\r\n\r\n".getBytes(StandardCharsets.UTF_8)); + outputStream.write(fileBytes); + outputStream.write(("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); + return outputStream.toByteArray(); + } + + protected String escapeQuoted(String value) { + return value == null ? "artifact.bin" : value.replace("\"", "\\\""); + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitBasicAuth.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitBasicAuth.java new file mode 100644 index 0000000..55024b5 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitBasicAuth.java @@ -0,0 +1,15 @@ +package org.openremote.extension.hawkbit.manager.hawkbit; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public final class HawkbitBasicAuth { + + private HawkbitBasicAuth() { + } + + public static String buildAuthorizationHeader(String username, String password) { + String credentials = (username == null ? "" : username) + ":" + (password == null ? "" : password); + return "Basic " + Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java new file mode 100644 index 0000000..fea245c --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java @@ -0,0 +1,54 @@ +package org.openremote.extension.hawkbit.manager.hawkbit; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetType; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypes; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleType; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Path("distributionsettypes") +public interface HawkbitDistributionSetTypesResource { + + String APPLICATION_HAL_JSON = "application/hal+json"; + + @POST + @Consumes(APPLICATION_HAL_JSON) + @Produces(APPLICATION_HAL_JSON) + FirmwareDistributionSetType[] create(FirmwareDistributionSetType[] distributionSetTypes); + + @GET + @Produces(APPLICATION_JSON) + FirmwareDistributionSetTypes getDistributionSetTypes(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + FirmwareDistributionSetType get(@PathParam("id") Long id); + + @GET + @Path("{id}/mandatorymoduletypes") + @Produces(APPLICATION_JSON) + FirmwareSoftwareModuleType[] getMandatoryModuleTypes(@PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}/optionalmoduletypes") + @Produces(APPLICATION_JSON) + FirmwareSoftwareModuleType[] getOptionalModuleTypes(@PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @DELETE + @Path("{id}") + void delete(@PathParam("id") Long id); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java new file mode 100644 index 0000000..55133ac --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java @@ -0,0 +1,49 @@ +package org.openremote.extension.hawkbit.manager.hawkbit; + +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetAssignmentResult; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetAssignment; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSets; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Path("distributionsets") +public interface HawkbitDistributionSetsResource { + + String APPLICATION_HAL_JSON = "application/hal+json"; + + @POST + @Consumes(APPLICATION_HAL_JSON) + @Produces(APPLICATION_HAL_JSON) + FirmwareDistributionSet[] create(FirmwareDistributionSet[] distributionSets); + + @POST + @Path("{id}/assignedTargets") + @Consumes(APPLICATION_HAL_JSON) + @Produces(APPLICATION_HAL_JSON) + FirmwareDistributionSetAssignmentResult assignTargets(@PathParam("id") Long id, + @QueryParam("offline") Boolean offline, + FirmwareTargetAssignment[] targets); + + @GET + @Produces(APPLICATION_JSON) + FirmwareDistributionSets getDistributionSets(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + FirmwareDistributionSet get(@PathParam("id") Long id); + + @DELETE + @Path("{id}") + void delete(@PathParam("id") Long id); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java new file mode 100644 index 0000000..ebe4066 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java @@ -0,0 +1,39 @@ +package org.openremote.extension.hawkbit.manager.hawkbit; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleType; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypes; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Path("softwaremoduletypes") +public interface HawkbitSoftwareModuleTypesResource { + + String APPLICATION_HAL_JSON = "application/hal+json"; + + @POST + @Consumes(APPLICATION_HAL_JSON) + @Produces(APPLICATION_HAL_JSON) + FirmwareSoftwareModuleType[] create(FirmwareSoftwareModuleType[] softwareModuleTypes); + + @GET + @Produces(APPLICATION_JSON) + FirmwareSoftwareModuleTypes getSoftwareModuleTypes(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + FirmwareSoftwareModuleType get(@PathParam("id") Long id); + + @DELETE + @Path("{id}") + void delete(@PathParam("id") Long id); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java new file mode 100644 index 0000000..01a2bb1 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java @@ -0,0 +1,46 @@ +package org.openremote.extension.hawkbit.manager.hawkbit; + +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifacts; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModule; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModules; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Path("softwaremodules") +public interface HawkbitSoftwareModulesResource { + + String APPLICATION_HAL_JSON = "application/hal+json"; + + @POST + @Consumes(APPLICATION_HAL_JSON) + @Produces(APPLICATION_HAL_JSON) + FirmwareSoftwareModule[] create(FirmwareSoftwareModule[] softwareModules); + + @GET + @Produces(APPLICATION_JSON) + FirmwareSoftwareModules getSoftwareModules(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + FirmwareSoftwareModule get(@PathParam("id") Long id); + + @GET + @Path("{id}/artifacts") + @Produces(APPLICATION_JSON) + FirmwareArtifacts getArtifacts(@PathParam("id") Long id); + + @DELETE + @Path("{id}") + void delete(@PathParam("id") Long id); + +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java new file mode 100644 index 0000000..4cc507c --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java @@ -0,0 +1,67 @@ +package org.openremote.extension.hawkbit.manager.hawkbit; + +import jakarta.ws.rs.*; +import org.openremote.extension.hawkbit.model.firmware.FirmwareAction; +import org.openremote.extension.hawkbit.model.firmware.FirmwareActions; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTarget; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargets; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + + +@Path("targets") +public interface HawkbitTargetsResource { + @GET + @Produces(APPLICATION_JSON) + FirmwareTargets getTargets(@QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit); + + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + FirmwareTarget[] create(FirmwareTarget[] targets); + + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + FirmwareTarget get(@PathParam("id") String id); + + @PUT + @Path("{id}") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + FirmwareTarget update(@PathParam("id") String id, FirmwareTarget target); + + @DELETE + @Path("{id}") + void delete(@PathParam("id") String id); + + @GET + @Path("{id}/assignedDS") + @Produces(APPLICATION_JSON) + FirmwareDistributionSet getAssignedDs(@PathParam("id") String id); + + @GET + @Path("{id}/installedDS") + @Produces(APPLICATION_JSON) + FirmwareDistributionSet getInstalledDs(@PathParam("id") String id); + + @GET + @Path("{id}/actions") + @Produces("application/hal+json") + FirmwareActions getActions(@PathParam("id") String id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}/actions/{actionId}") + @Produces("application/hal+json") + FirmwareAction getAction(@PathParam("id") String id, @PathParam("actionId") Long actionId); + + @DELETE + @Path("{id}/actions/{actionId}") + void cancelAction(@PathParam("id") String id, + @PathParam("actionId") Long actionId, + @QueryParam("force") Boolean force); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java new file mode 100644 index 0000000..02509da --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java @@ -0,0 +1,157 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareAction { + protected Long id; + protected String status; + protected String type; + protected String forceType; + protected Long forceTime; + protected Integer weight; + protected Boolean active; + protected Long createdAt; + protected Long lastModifiedAt; + protected Integer lastStatusCode; + protected FirmwareDistributionSet distributionSet; + protected FirmwareMaintenanceWindow maintenanceWindow; + @JsonProperty("_links") + protected FirmwareActionLinks links; + + @JsonCreator + protected FirmwareAction() { + } + + public Long getId() { + return id; + } + + public FirmwareAction setId(Long id) { + this.id = id; + return this; + } + + public String getStatus() { + return status; + } + + public FirmwareAction setStatus(String status) { + this.status = status; + return this; + } + + public String getType() { + return type; + } + + public FirmwareAction setType(String type) { + this.type = type; + return this; + } + + public String getForceType() { + return forceType; + } + + public FirmwareAction setForceType(String forceType) { + this.forceType = forceType; + return this; + } + + public Long getForceTime() { + return forceTime; + } + + public FirmwareAction setForceTime(Long forceTime) { + this.forceTime = forceTime; + return this; + } + + public Integer getWeight() { + return weight; + } + + public FirmwareAction setWeight(Integer weight) { + this.weight = weight; + return this; + } + + public Boolean getActive() { + return active; + } + + public FirmwareAction setActive(Boolean active) { + this.active = active; + return this; + } + + public Long getCreatedAt() { + return createdAt; + } + + public FirmwareAction setCreatedAt(Long createdAt) { + this.createdAt = createdAt; + return this; + } + + public Long getLastModifiedAt() { + return lastModifiedAt; + } + + public FirmwareAction setLastModifiedAt(Long lastModifiedAt) { + this.lastModifiedAt = lastModifiedAt; + return this; + } + + public Integer getLastStatusCode() { + return lastStatusCode; + } + + public FirmwareAction setLastStatusCode(Integer lastStatusCode) { + this.lastStatusCode = lastStatusCode; + return this; + } + + public FirmwareDistributionSet getDistributionSet() { + return distributionSet; + } + + public FirmwareAction setDistributionSet(FirmwareDistributionSet distributionSet) { + this.distributionSet = distributionSet; + return this; + } + + public FirmwareMaintenanceWindow getMaintenanceWindow() { + return maintenanceWindow; + } + + public FirmwareAction setMaintenanceWindow(FirmwareMaintenanceWindow maintenanceWindow) { + this.maintenanceWindow = maintenanceWindow; + return this; + } + + public FirmwareActionLinks getLinks() { + return links; + } + + public FirmwareAction setLinks(FirmwareActionLinks links) { + this.links = links; + return this; + } + + public Long getDistributionSetId() { + if (links == null || links.getDistributionset() == null || links.getDistributionset().getHref() == null) { + return null; + } + String href = links.getDistributionset().getHref(); + String[] parts = href.split("/"); + try { + return Long.parseLong(parts[parts.length - 1]); + } catch (NumberFormatException e) { + return null; + } + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java new file mode 100644 index 0000000..8d5b8dc --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java @@ -0,0 +1,22 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareActionLinks { + protected FirmwareLink distributionset; + + @JsonCreator + protected FirmwareActionLinks() { + } + + public FirmwareLink getDistributionset() { + return distributionset; + } + + public FirmwareActionLinks setDistributionset(FirmwareLink distributionset) { + this.distributionset = distributionset; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java new file mode 100644 index 0000000..f7e9585 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java @@ -0,0 +1,44 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareActions { + protected List content; + protected int total; + protected int size; + + @JsonCreator + protected FirmwareActions() { + } + + public List getContent() { + return content; + } + + public FirmwareActions setContent(List content) { + this.content = content; + return this; + } + + public int getTotal() { + return total; + } + + public FirmwareActions setTotal(int total) { + this.total = total; + return this; + } + + public int getSize() { + return size; + } + + public FirmwareActions setSize(int size) { + this.size = size; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java new file mode 100644 index 0000000..716edef --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java @@ -0,0 +1,64 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.Map; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareArtifact { + protected Long id; + protected String providedFilename; + protected Long size; + protected Map hashes; + protected FirmwareArtifactLinks _links; + + @JsonCreator + protected FirmwareArtifact() { + } + + public Long getId() { + return id; + } + + public FirmwareArtifact setId(Long id) { + this.id = id; + return this; + } + + public String getProvidedFilename() { + return providedFilename; + } + + public FirmwareArtifact setProvidedFilename(String providedFilename) { + this.providedFilename = providedFilename; + return this; + } + + public Long getSize() { + return size; + } + + public FirmwareArtifact setSize(Long size) { + this.size = size; + return this; + } + + public Map getHashes() { + return hashes; + } + + public FirmwareArtifact setHashes(Map hashes) { + this.hashes = hashes; + return this; + } + + public FirmwareArtifactLinks get_links() { + return _links; + } + + public FirmwareArtifact set_links(FirmwareArtifactLinks links) { + this._links = links; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java new file mode 100644 index 0000000..9a82d40 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java @@ -0,0 +1,32 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareArtifactLinks { + protected FirmwareLink self; + protected FirmwareLink download; + + @JsonCreator + protected FirmwareArtifactLinks() { + } + + public FirmwareLink getSelf() { + return self; + } + + public FirmwareArtifactLinks setSelf(FirmwareLink self) { + this.self = self; + return this; + } + + public FirmwareLink getDownload() { + return download; + } + + public FirmwareArtifactLinks setDownload(FirmwareLink download) { + this.download = download; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java new file mode 100644 index 0000000..093af75 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java @@ -0,0 +1,44 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareArtifacts { + protected List content; + + protected FirmwareArtifacts() { + } + + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public FirmwareArtifacts(List content) { + this.content = content; + } + + public List getContent() { + return content; + } + + public FirmwareArtifacts setContent(List content) { + this.content = content; + return this; + } + + public int getTotal() { + return content == null ? 0 : content.size(); + } + + public FirmwareArtifacts setTotal(int total) { + return this; + } + + public int getSize() { + return content == null ? 0 : content.size(); + } + + public FirmwareArtifacts setSize(int size) { + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAssignedAction.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAssignedAction.java new file mode 100644 index 0000000..eb81402 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAssignedAction.java @@ -0,0 +1,22 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareAssignedAction { + protected Long id; + + @JsonCreator + protected FirmwareAssignedAction() { + } + + public Long getId() { + return id; + } + + public FirmwareAssignedAction setId(Long id) { + this.id = id; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java new file mode 100644 index 0000000..25c3766 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java @@ -0,0 +1,134 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonCreator; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareDistributionSet { + protected Long id; + protected String name; + protected String description; + protected String version; + protected String type; + protected String typeName; + protected Boolean locked; + protected Boolean deleted; + protected Boolean valid; + protected Boolean complete; + protected Boolean requiredMigrationStep; + protected List modules; + + @JsonCreator + protected FirmwareDistributionSet() { + } + + public Long getId() { + return id; + } + + public FirmwareDistributionSet setId(Long id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public FirmwareDistributionSet setName(String name) { + this.name = name; + return this; + } + + public String getDescription() { + return description; + } + + public FirmwareDistributionSet setDescription(String description) { + this.description = description; + return this; + } + + public String getVersion() { + return version; + } + + public FirmwareDistributionSet setVersion(String version) { + this.version = version; + return this; + } + + public String getType() { + return type; + } + + public FirmwareDistributionSet setType(String type) { + this.type = type; + return this; + } + + public String getTypeName() { + return typeName; + } + + public FirmwareDistributionSet setTypeName(String typeName) { + this.typeName = typeName; + return this; + } + + public Boolean getLocked() { + return locked; + } + + public FirmwareDistributionSet setLocked(Boolean locked) { + this.locked = locked; + return this; + } + + public Boolean getDeleted() { + return deleted; + } + + public FirmwareDistributionSet setDeleted(Boolean deleted) { + this.deleted = deleted; + return this; + } + + public Boolean getValid() { + return valid; + } + + public FirmwareDistributionSet setValid(Boolean valid) { + this.valid = valid; + return this; + } + + public Boolean getComplete() { + return complete; + } + + public FirmwareDistributionSet setComplete(Boolean complete) { + this.complete = complete; + return this; + } + + public Boolean getRequiredMigrationStep() { + return requiredMigrationStep; + } + + public FirmwareDistributionSet setRequiredMigrationStep(Boolean requiredMigrationStep) { + this.requiredMigrationStep = requiredMigrationStep; + return this; + } + + public List getModules() { + return modules; + } + + public FirmwareDistributionSet setModules(List modules) { + this.modules = modules; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java new file mode 100644 index 0000000..5f521c6 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java @@ -0,0 +1,84 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareDistributionSetAssignment { + protected List targets; + protected Boolean offline; + protected Long forcetime; + protected Integer weight; + protected Boolean confirmationRequired; + protected String type; + protected FirmwareMaintenanceWindow maintenanceWindow; + + @JsonCreator + protected FirmwareDistributionSetAssignment() { + } + + public List getTargets() { + return targets; + } + + public FirmwareDistributionSetAssignment setTargets(List targets) { + this.targets = targets; + return this; + } + + public Boolean getOffline() { + return offline; + } + + public FirmwareDistributionSetAssignment setOffline(Boolean offline) { + this.offline = offline; + return this; + } + + public Long getForcetime() { + return forcetime; + } + + public FirmwareDistributionSetAssignment setForcetime(Long forcetime) { + this.forcetime = forcetime; + return this; + } + + public Integer getWeight() { + return weight; + } + + public FirmwareDistributionSetAssignment setWeight(Integer weight) { + this.weight = weight; + return this; + } + + public Boolean getConfirmationRequired() { + return confirmationRequired; + } + + public FirmwareDistributionSetAssignment setConfirmationRequired(Boolean confirmationRequired) { + this.confirmationRequired = confirmationRequired; + return this; + } + + public String getType() { + return type; + } + + public FirmwareDistributionSetAssignment setType(String type) { + this.type = type; + return this; + } + + public FirmwareMaintenanceWindow getMaintenanceWindow() { + return maintenanceWindow; + } + + public FirmwareDistributionSetAssignment setMaintenanceWindow(FirmwareMaintenanceWindow maintenanceWindow) { + this.maintenanceWindow = maintenanceWindow; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java new file mode 100644 index 0000000..a9ecb17 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java @@ -0,0 +1,54 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareDistributionSetAssignmentResult { + protected Integer alreadyAssigned; + protected Integer assigned; + protected Integer total; + protected List assignedActions; + + @JsonCreator + protected FirmwareDistributionSetAssignmentResult() { + } + + public Integer getAlreadyAssigned() { + return alreadyAssigned; + } + + public FirmwareDistributionSetAssignmentResult setAlreadyAssigned(Integer alreadyAssigned) { + this.alreadyAssigned = alreadyAssigned; + return this; + } + + public Integer getAssigned() { + return assigned; + } + + public FirmwareDistributionSetAssignmentResult setAssigned(Integer assigned) { + this.assigned = assigned; + return this; + } + + public Integer getTotal() { + return total; + } + + public FirmwareDistributionSetAssignmentResult setTotal(Integer total) { + this.total = total; + return this; + } + + public List getAssignedActions() { + return assignedActions; + } + + public FirmwareDistributionSetAssignmentResult setAssignedActions(List assignedActions) { + this.assignedActions = assignedActions; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java new file mode 100644 index 0000000..b4eae3a --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java @@ -0,0 +1,57 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.security.RolesAllowed; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; + +import org.openremote.model.Constants; +import org.openremote.model.http.RequestParams; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Tag(name = "Firmware Distribution Sets", description = "Management of firmware distribution sets") +@Path("firmware/distributionset") +public interface FirmwareDistributionSetResource { + + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + FirmwareDistributionSet createDistributionSet(@BeanParam RequestParams requestParams, + FirmwareDistributionSet distributionSet); + + @POST + @Path("{id}/assign") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + FirmwareDistributionSetAssignmentResult assignDistributionSet(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + FirmwareDistributionSetAssignment assignment); + + @GET + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareDistributionSets getDistributionSets(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareDistributionSet getDistributionSet(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + + @DELETE + @Path("{id}") + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + void deleteDistributionSet(@BeanParam RequestParams requestParams, @PathParam("id") Long id); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java new file mode 100644 index 0000000..70b04f3 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java @@ -0,0 +1,103 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareDistributionSetType { + protected Long id; + protected String name; + protected String description; + protected String key; + protected String colour; + protected Boolean deleted; + @JsonProperty("mandatorymodules") + protected List mandatoryModules; + @JsonProperty("optionalmodules") + protected List optionalModules; + + @JsonCreator + protected FirmwareDistributionSetType() { + } + + public Long getId() { + return id; + } + + public FirmwareDistributionSetType setId(Long id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public FirmwareDistributionSetType setName(String name) { + this.name = name; + return this; + } + + public String getDescription() { + return description; + } + + public FirmwareDistributionSetType setDescription(String description) { + this.description = description; + return this; + } + + public String getKey() { + return key; + } + + public FirmwareDistributionSetType setKey(String key) { + this.key = key; + return this; + } + + public String getColour() { + return colour; + } + + public FirmwareDistributionSetType setColour(String colour) { + this.colour = colour; + return this; + } + + public Boolean getDeleted() { + return deleted; + } + + public FirmwareDistributionSetType setDeleted(Boolean deleted) { + this.deleted = deleted; + return this; + } + + @JsonProperty("mandatorymodules") + public List getMandatoryModules() { + return mandatoryModules; + } + + @JsonProperty("mandatorymodules") + public FirmwareDistributionSetType setMandatoryModules( + List mandatoryModules) { + this.mandatoryModules = mandatoryModules; + return this; + } + + @JsonProperty("optionalmodules") + public List getOptionalModules() { + return optionalModules; + } + + @JsonProperty("optionalmodules") + public FirmwareDistributionSetType setOptionalModules( + List optionalModules) { + this.optionalModules = optionalModules; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java new file mode 100644 index 0000000..93b5592 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java @@ -0,0 +1,67 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.security.RolesAllowed; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; + +import org.openremote.model.Constants; +import org.openremote.model.http.RequestParams; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Tag(name = "Firmware Distribution Set Types", description = "Management of firmware distribution set types") +@Path("firmware/distributionsettype") +public interface FirmwareDistributionSetTypeResource { + + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + FirmwareDistributionSetType createDistributionSetType(@BeanParam RequestParams requestParams, + FirmwareDistributionSetType distributionSetType); + + @GET + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareDistributionSetTypes getDistributionSetTypes(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareDistributionSetType getDistributionSetType(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); + + @GET + @Path("{id}/mandatorymoduletypes") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareSoftwareModuleType[] getMandatoryModuleTypes(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}/optionalmoduletypes") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareSoftwareModuleType[] getOptionalModuleTypes(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @DELETE + @Path("{id}") + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + void deleteDistributionSetType(@BeanParam RequestParams requestParams, @PathParam("id") Long id); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java new file mode 100644 index 0000000..02049f0 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java @@ -0,0 +1,44 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareDistributionSetTypes { + protected List content; + protected int total; + protected int size; + + @JsonCreator + protected FirmwareDistributionSetTypes() { + } + + public List getContent() { + return content; + } + + public FirmwareDistributionSetTypes setContent(List content) { + this.content = content; + return this; + } + + public int getTotal() { + return total; + } + + public FirmwareDistributionSetTypes setTotal(int total) { + this.total = total; + return this; + } + + public int getSize() { + return size; + } + + public FirmwareDistributionSetTypes setSize(int size) { + this.size = size; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java new file mode 100644 index 0000000..9291968 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java @@ -0,0 +1,44 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareDistributionSets { + protected List content; + protected int total; + protected int size; + + @JsonCreator + protected FirmwareDistributionSets() { + } + + public List getContent() { + return content; + } + + public FirmwareDistributionSets setContent(List content) { + this.content = content; + return this; + } + + public int getTotal() { + return total; + } + + public FirmwareDistributionSets setTotal(int total) { + this.total = total; + return this; + } + + public int getSize() { + return size; + } + + public FirmwareDistributionSets setSize(int size) { + this.size = size; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java new file mode 100644 index 0000000..e5301dc --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java @@ -0,0 +1,32 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareLink { + protected String href; + protected String name; + + @JsonCreator + protected FirmwareLink() { + } + + public String getHref() { + return href; + } + + public FirmwareLink setHref(String href) { + this.href = href; + return this; + } + + public String getName() { + return name; + } + + public FirmwareLink setName(String name) { + this.name = name; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java new file mode 100644 index 0000000..3176cf7 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java @@ -0,0 +1,42 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareMaintenanceWindow { + protected String schedule; + protected String duration; + protected String timezone; + + @JsonCreator + protected FirmwareMaintenanceWindow() { + } + + public String getSchedule() { + return schedule; + } + + public FirmwareMaintenanceWindow setSchedule(String schedule) { + this.schedule = schedule; + return this; + } + + public String getDuration() { + return duration; + } + + public FirmwareMaintenanceWindow setDuration(String duration) { + this.duration = duration; + return this; + } + + public String getTimezone() { + return timezone; + } + + public FirmwareMaintenanceWindow setTimezone(String timezone) { + this.timezone = timezone; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java new file mode 100644 index 0000000..d8ad49f --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java @@ -0,0 +1,20 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import org.openremote.model.util.TsIgnore; +import org.openremote.model.value.MetaItemDescriptor; +import org.openremote.model.value.ValueType; + +@TsIgnore +public final class FirmwareMetaItemType { + + private FirmwareMetaItemType() { + } + + /** + * Can be used on a {@link ValueType#TEXT} attribute to indicate that the parent asset should be synced as a + * firmware target to hawkBit, enabling firmware updates and DDI interactions. The attribute value will be + * updated with target details from hawkBit. + */ + public static final MetaItemDescriptor FIRMWARE_TARGET = new MetaItemDescriptor<>( + "firmwareTarget", ValueType.BOOLEAN); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java new file mode 100644 index 0000000..e1ecd7e --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java @@ -0,0 +1,42 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwarePollStatus { + protected Long lastRequestAt; + protected Long nextExpectedRequestAt; + protected Boolean overdue; + + @JsonCreator + protected FirmwarePollStatus() { + } + + public Long getLastRequestAt() { + return lastRequestAt; + } + + public FirmwarePollStatus setLastRequestAt(Long lastRequestAt) { + this.lastRequestAt = lastRequestAt; + return this; + } + + public Long getNextExpectedRequestAt() { + return nextExpectedRequestAt; + } + + public FirmwarePollStatus setNextExpectedRequestAt(Long nextExpectedRequestAt) { + this.nextExpectedRequestAt = nextExpectedRequestAt; + return this; + } + + public Boolean getOverdue() { + return overdue; + } + + public FirmwarePollStatus setOverdue(Boolean overdue) { + this.overdue = overdue; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java new file mode 100644 index 0000000..34d4b1d --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java @@ -0,0 +1,122 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareSoftwareModule { + protected Long id; + protected String name; + protected String description; + protected String version; + protected String type; + protected String typeName; + protected String vendor; + protected Boolean encrypted; + protected Boolean locked; + protected Boolean deleted; + protected Boolean complete; + + @JsonCreator + protected FirmwareSoftwareModule() { + } + + public Long getId() { + return id; + } + + public FirmwareSoftwareModule setId(Long id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public FirmwareSoftwareModule setName(String name) { + this.name = name; + return this; + } + + public String getDescription() { + return description; + } + + public FirmwareSoftwareModule setDescription(String description) { + this.description = description; + return this; + } + + public String getVersion() { + return version; + } + + public FirmwareSoftwareModule setVersion(String version) { + this.version = version; + return this; + } + + public String getType() { + return type; + } + + public FirmwareSoftwareModule setType(String type) { + this.type = type; + return this; + } + + public String getTypeName() { + return typeName; + } + + public FirmwareSoftwareModule setTypeName(String typeName) { + this.typeName = typeName; + return this; + } + + public String getVendor() { + return vendor; + } + + public FirmwareSoftwareModule setVendor(String vendor) { + this.vendor = vendor; + return this; + } + + public Boolean getEncrypted() { + return encrypted; + } + + public FirmwareSoftwareModule setEncrypted(Boolean encrypted) { + this.encrypted = encrypted; + return this; + } + + public Boolean getLocked() { + return locked; + } + + public FirmwareSoftwareModule setLocked(Boolean locked) { + this.locked = locked; + return this; + } + + public Boolean getDeleted() { + return deleted; + } + + public FirmwareSoftwareModule setDeleted(Boolean deleted) { + this.deleted = deleted; + return this; + } + + public Boolean getComplete() { + return complete; + } + + public FirmwareSoftwareModule setComplete(Boolean complete) { + this.complete = complete; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java new file mode 100644 index 0000000..89dc43d --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java @@ -0,0 +1,69 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.security.RolesAllowed; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.EntityPart; + +import org.openremote.model.Constants; +import org.openremote.model.http.RequestParams; + +import java.util.List; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.MediaType.MULTIPART_FORM_DATA; + +@Tag(name = "Firmware Software Modules", description = "Management of firmware software modules") +@Path("firmware/softwaremodule") +public interface FirmwareSoftwareModuleResource { + + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + FirmwareSoftwareModule createSoftwareModule(@BeanParam RequestParams requestParams, + FirmwareSoftwareModule softwareModule); + + @GET + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareSoftwareModules getSoftwareModules(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareSoftwareModule getSoftwareModule(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + + @GET + @Path("{id}/artifacts") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareArtifacts getSoftwareModuleArtifacts(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + + @POST + @Path("{id}/artifacts") + @Consumes(MULTIPART_FORM_DATA) + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + FirmwareArtifact uploadSoftwareModuleArtifact(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + @QueryParam("filename") String filename, + List parts); + + @DELETE + @Path("{id}") + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + void deleteSoftwareModule(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java new file mode 100644 index 0000000..1770bba --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java @@ -0,0 +1,92 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareSoftwareModuleType { + protected Long id; + protected String name; + protected String description; + protected String key; + protected Integer minArtifacts; + protected Integer maxAssignments; + protected String colour; + protected Boolean deleted; + + @JsonCreator + protected FirmwareSoftwareModuleType() { + } + + public Long getId() { + return id; + } + + public FirmwareSoftwareModuleType setId(Long id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public FirmwareSoftwareModuleType setName(String name) { + this.name = name; + return this; + } + + public String getDescription() { + return description; + } + + public FirmwareSoftwareModuleType setDescription(String description) { + this.description = description; + return this; + } + + public String getKey() { + return key; + } + + public FirmwareSoftwareModuleType setKey(String key) { + this.key = key; + return this; + } + + public Integer getMinArtifacts() { + return minArtifacts; + } + + public FirmwareSoftwareModuleType setMinArtifacts(Integer minArtifacts) { + this.minArtifacts = minArtifacts; + return this; + } + + public Integer getMaxAssignments() { + return maxAssignments; + } + + public FirmwareSoftwareModuleType setMaxAssignments(Integer maxAssignments) { + this.maxAssignments = maxAssignments; + return this; + } + + public String getColour() { + return colour; + } + + public FirmwareSoftwareModuleType setColour(String colour) { + this.colour = colour; + return this; + } + + public Boolean getDeleted() { + return deleted; + } + + public FirmwareSoftwareModuleType setDeleted(Boolean deleted) { + this.deleted = deleted; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java new file mode 100644 index 0000000..8dd3f03 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java @@ -0,0 +1,22 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareSoftwareModuleTypeAssignment { + protected Long id; + + @JsonCreator + protected FirmwareSoftwareModuleTypeAssignment() { + } + + public Long getId() { + return id; + } + + public FirmwareSoftwareModuleTypeAssignment setId(Long id) { + this.id = id; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java new file mode 100644 index 0000000..8775ae2 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java @@ -0,0 +1,49 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.security.RolesAllowed; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; + +import org.openremote.model.Constants; +import org.openremote.model.http.RequestParams; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Tag(name = "Firmware Software Module Types", description = "Management of firmware software module types") +@Path("firmware/softwaremoduletype") +public interface FirmwareSoftwareModuleTypeResource { + + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + FirmwareSoftwareModuleType createSoftwareModuleType(@BeanParam RequestParams requestParams, + FirmwareSoftwareModuleType softwareModuleType); + + @GET + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareSoftwareModuleTypes getSoftwareModuleTypes(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareSoftwareModuleType getSoftwareModuleType(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); + + @DELETE + @Path("{id}") + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + void deleteSoftwareModuleType(@BeanParam RequestParams requestParams, @PathParam("id") Long id); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java new file mode 100644 index 0000000..fc529b0 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java @@ -0,0 +1,44 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareSoftwareModuleTypes { + protected List content; + protected int total; + protected int size; + + @JsonCreator + protected FirmwareSoftwareModuleTypes() { + } + + public List getContent() { + return content; + } + + public FirmwareSoftwareModuleTypes setContent(List content) { + this.content = content; + return this; + } + + public int getTotal() { + return total; + } + + public FirmwareSoftwareModuleTypes setTotal(int total) { + this.total = total; + return this; + } + + public int getSize() { + return size; + } + + public FirmwareSoftwareModuleTypes setSize(int size) { + this.size = size; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java new file mode 100644 index 0000000..d037809 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java @@ -0,0 +1,44 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareSoftwareModules { + protected List content; + protected int total; + protected int size; + + @JsonCreator + protected FirmwareSoftwareModules() { + } + + public List getContent() { + return content; + } + + public FirmwareSoftwareModules setContent(List content) { + this.content = content; + return this; + } + + public int getTotal() { + return total; + } + + public FirmwareSoftwareModules setTotal(int total) { + this.total = total; + return this; + } + + public int getSize() { + return size; + } + + public FirmwareSoftwareModules setSize(int size) { + this.size = size; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java new file mode 100644 index 0000000..bf6f636 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java @@ -0,0 +1,158 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareTarget { + protected String controllerId; + protected String name; + protected String description; + protected String securityToken; + protected String updateStatus; + protected Long lastControllerRequestAt; + protected Long installedAt; + protected String ipAddress; + protected String address; + protected FirmwarePollStatus pollStatus; + protected Boolean requestAttributes; + protected Long targetType; + protected String targetTypeName; + protected Boolean autoConfirmActive; + + @JsonCreator + protected FirmwareTarget() { + } + + public FirmwareTarget(String controllerId, String name, String description) { + this.controllerId = controllerId; + this.name = name; + this.description = description; + } + + public String getControllerId() { + return controllerId; + } + + public FirmwareTarget setControllerId(String controllerId) { + this.controllerId = controllerId; + return this; + } + + public String getName() { + return name; + } + + public FirmwareTarget setName(String name) { + this.name = name; + return this; + } + + public String getDescription() { + return description; + } + + public FirmwareTarget setDescription(String description) { + this.description = description; + return this; + } + + public String getSecurityToken() { + return securityToken; + } + + public FirmwareTarget setSecurityToken(String securityToken) { + this.securityToken = securityToken; + return this; + } + + public String getUpdateStatus() { + return updateStatus; + } + + public FirmwareTarget setUpdateStatus(String updateStatus) { + this.updateStatus = updateStatus; + return this; + } + + public Long getLastControllerRequestAt() { + return lastControllerRequestAt; + } + + public FirmwareTarget setLastControllerRequestAt(Long lastControllerRequestAt) { + this.lastControllerRequestAt = lastControllerRequestAt; + return this; + } + + public Long getInstalledAt() { + return installedAt; + } + + public FirmwareTarget setInstalledAt(Long installedAt) { + this.installedAt = installedAt; + return this; + } + + public String getIpAddress() { + return ipAddress; + } + + public FirmwareTarget setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + public String getAddress() { + return address; + } + + public FirmwareTarget setAddress(String address) { + this.address = address; + return this; + } + + public FirmwarePollStatus getPollStatus() { + return pollStatus; + } + + public FirmwareTarget setPollStatus(FirmwarePollStatus pollStatus) { + this.pollStatus = pollStatus; + return this; + } + + public Boolean getRequestAttributes() { + return requestAttributes; + } + + public FirmwareTarget setRequestAttributes(Boolean requestAttributes) { + this.requestAttributes = requestAttributes; + return this; + } + + public Long getTargetType() { + return targetType; + } + + public FirmwareTarget setTargetType(Long targetType) { + this.targetType = targetType; + return this; + } + + public String getTargetTypeName() { + return targetTypeName; + } + + public FirmwareTarget setTargetTypeName(String targetTypeName) { + this.targetTypeName = targetTypeName; + return this; + } + + public Boolean getAutoConfirmActive() { + return autoConfirmActive; + } + + public FirmwareTarget setAutoConfirmActive(Boolean autoConfirmActive) { + this.autoConfirmActive = autoConfirmActive; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java new file mode 100644 index 0000000..077de5c --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java @@ -0,0 +1,72 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareTargetAssignment { + protected String id; + protected Long forcetime; + protected Integer weight; + protected Boolean confirmationRequired; + protected String type; + protected FirmwareMaintenanceWindow maintenanceWindow; + + @JsonCreator + public FirmwareTargetAssignment() { + } + + public String getId() { + return id; + } + + public FirmwareTargetAssignment setId(String id) { + this.id = id; + return this; + } + + public Long getForcetime() { + return forcetime; + } + + public FirmwareTargetAssignment setForcetime(Long forcetime) { + this.forcetime = forcetime; + return this; + } + + public Integer getWeight() { + return weight; + } + + public FirmwareTargetAssignment setWeight(Integer weight) { + this.weight = weight; + return this; + } + + public Boolean getConfirmationRequired() { + return confirmationRequired; + } + + public FirmwareTargetAssignment setConfirmationRequired(Boolean confirmationRequired) { + this.confirmationRequired = confirmationRequired; + return this; + } + + public String getType() { + return type; + } + + public FirmwareTargetAssignment setType(String type) { + this.type = type; + return this; + } + + public FirmwareMaintenanceWindow getMaintenanceWindow() { + return maintenanceWindow; + } + + public FirmwareTargetAssignment setMaintenanceWindow(FirmwareMaintenanceWindow maintenanceWindow) { + this.maintenanceWindow = maintenanceWindow; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java new file mode 100644 index 0000000..f88feec --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java @@ -0,0 +1,71 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import jakarta.annotation.security.RolesAllowed; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; + +import org.openremote.model.Constants; +import org.openremote.model.http.RequestParams; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import io.swagger.v3.oas.annotations.tags.Tag; + +@Tag(name = "Firmware Targets", description = "Management of firmware targets") +@Path("firmware/target") +public interface FirmwareTargetResource { + + @GET + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareTargets getTargets(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareTarget getTarget(@BeanParam RequestParams requestParams, @PathParam("id") String id); + + @GET + @Path("{id}/assignedDS") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareDistributionSet getAssignedDs(@BeanParam RequestParams requestParams, @PathParam("id") String id); + + @GET + @Path("{id}/installedDS") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareDistributionSet getInstalledDs(@BeanParam RequestParams requestParams, @PathParam("id") String id); + + @GET + @Path("{id}/actions") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareActions getActions(@BeanParam RequestParams requestParams, + @PathParam("id") String id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}/actions/{actionId}") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareAction getAction(@BeanParam RequestParams requestParams, + @PathParam("id") String id, + @PathParam("actionId") Long actionId); + + @DELETE + @Path("{id}/actions/{actionId}") + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + void cancelAction(@BeanParam RequestParams requestParams, + @PathParam("id") String id, + @PathParam("actionId") Long actionId, + @QueryParam("force") Boolean force); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java new file mode 100644 index 0000000..eecd450 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java @@ -0,0 +1,44 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareTargets { + protected List content; + protected int total; + protected int size; + + @JsonCreator + protected FirmwareTargets() { + } + + public List getContent() { + return content; + } + + public FirmwareTargets setContent(List content) { + this.content = content; + return this; + } + + public int getTotal() { + return total; + } + + public FirmwareTargets setTotal(int total) { + this.total = total; + return this; + } + + public int getSize() { + return size; + } + + public FirmwareTargets setSize(int size) { + this.size = size; + return this; + } +} diff --git a/hawkbit/src/main/resources/META-INF/services/org.openremote.model.ContainerService b/hawkbit/src/main/resources/META-INF/services/org.openremote.model.ContainerService new file mode 100644 index 0000000..5050c88 --- /dev/null +++ b/hawkbit/src/main/resources/META-INF/services/org.openremote.model.ContainerService @@ -0,0 +1 @@ +org.openremote.extension.hawkbit.manager.firmware.FirmwareService From 1e4aee67443fe7c9b55065afad89431afee4fc56 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Thu, 7 May 2026 12:32:53 +0200 Subject: [PATCH 02/18] Rollouts and target filters --- .../firmware/FirmwareRolloutResourceImpl.java | 109 ++++++++ .../manager/firmware/FirmwareService.java | 10 + .../FirmwareTargetFilterResourceImpl.java | 101 ++++++++ .../hawkbit/HawkbitRolloutsResource.java | 66 +++++ .../hawkbit/HawkbitTargetFiltersResource.java | 58 +++++ .../firmware/FirmwareAutoAssignRequest.java | 52 ++++ .../model/firmware/FirmwareRollout.java | 244 ++++++++++++++++++ .../model/firmware/FirmwareRolloutAction.java | 32 +++ .../firmware/FirmwareRolloutCondition.java | 32 +++ .../model/firmware/FirmwareRolloutGroup.java | 144 +++++++++++ .../model/firmware/FirmwareRolloutGroups.java | 44 ++++ .../firmware/FirmwareRolloutRequest.java | 152 +++++++++++ .../firmware/FirmwareRolloutResource.java | 81 ++++++ .../model/firmware/FirmwareRollouts.java | 44 ++++ .../firmware/FirmwareTargetFilterQueries.java | 44 ++++ .../firmware/FirmwareTargetFilterQuery.java | 82 ++++++ .../FirmwareTargetFilterQueryRequest.java | 32 +++ .../FirmwareTargetFilterResource.java | 72 ++++++ 18 files changed, 1399 insertions(+) create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java new file mode 100644 index 0000000..8d04248 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java @@ -0,0 +1,109 @@ +package org.openremote.extension.hawkbit.manager.firmware; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import org.openremote.container.timer.TimerService; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.manager.web.ManagerWebResource; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRollout; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutGroup; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutGroups; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutRequest; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutResource; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRollouts; +import org.openremote.model.http.RequestParams; + +public class FirmwareRolloutResourceImpl extends ManagerWebResource + implements FirmwareRolloutResource { + + protected final FirmwareService firmwareService; + + public FirmwareRolloutResourceImpl(TimerService timerService, ManagerIdentityService identityService, + FirmwareService firmwareService) { + super(timerService, identityService); + this.firmwareService = firmwareService; + } + + @Override + public FirmwareRollouts getRollouts(RequestParams requestParams, Integer offset, Integer limit) { + try { + // Request full representation so totalTargetsPerStatus and totalGroups are populated; hawkBit defaults to compact. + return firmwareService.rolloutsResource.getRollouts(offset, limit, "full"); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware rollouts", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareRollout getRollout(RequestParams requestParams, Long id) { + try { + return firmwareService.rolloutsResource.get(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware rollout '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareRollout createRollout(RequestParams requestParams, FirmwareRolloutRequest rollout) { + try { + return firmwareService.rolloutsResource.create(rollout); + } catch (Exception e) { + throw new WebApplicationException("Failed to create firmware rollout", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public void deleteRollout(RequestParams requestParams, Long id) { + try { + firmwareService.rolloutsResource.delete(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to delete firmware rollout '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareRollout startRollout(RequestParams requestParams, Long id) { + try { + return firmwareService.rolloutsResource.start(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to start firmware rollout '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public void pauseRollout(RequestParams requestParams, Long id) { + try { + firmwareService.rolloutsResource.pause(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to pause firmware rollout '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareRolloutGroups getRolloutGroups(RequestParams requestParams, Long id, + Integer offset, Integer limit) { + try { + return firmwareService.rolloutsResource.getRolloutGroups(id, offset, limit, "full"); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve groups for rollout '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareRolloutGroup getRolloutGroup(RequestParams requestParams, Long id, Long groupId) { + try { + return firmwareService.rolloutsResource.getRolloutGroup(id, groupId); + } catch (Exception e) { + throw new WebApplicationException( + "Failed to retrieve group '" + groupId + "' for rollout '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java index a908caf..e9dc341 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java @@ -50,8 +50,10 @@ import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitBasicAuth; import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitDistributionSetsResource; import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitDistributionSetTypesResource; +import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitRolloutsResource; import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitSoftwareModulesResource; import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitSoftwareModuleTypesResource; +import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitTargetFiltersResource; import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitTargetsResource; import org.openremote.manager.web.ManagerWebService; import org.openremote.model.Container; @@ -96,6 +98,8 @@ public class FirmwareService implements ContainerService { protected HawkbitDistributionSetTypesResource distributionSetTypesResource; protected HawkbitSoftwareModulesResource softwareModulesResource; protected HawkbitSoftwareModuleTypesResource softwareModuleTypesResource; + protected HawkbitRolloutsResource rolloutsResource; + protected HawkbitTargetFiltersResource targetFiltersResource; protected HawkbitArtifactUploadClient artifactUploadClient; static { @@ -128,6 +132,10 @@ public void init(Container container) throws Exception { new FirmwareSoftwareModuleResourceImpl(timerService, identityService, this)); container.getService(ManagerWebService.class).addApiSingleton( new FirmwareSoftwareModuleTypeResourceImpl(timerService, identityService, this)); + container.getService(ManagerWebService.class).addApiSingleton( + new FirmwareRolloutResourceImpl(timerService, identityService, this)); + container.getService(ManagerWebService.class).addApiSingleton( + new FirmwareTargetFilterResourceImpl(timerService, identityService, this)); } @Override @@ -171,6 +179,8 @@ public void start(Container container) throws Exception { distributionSetTypesResource = webTarget.proxy(HawkbitDistributionSetTypesResource.class); softwareModulesResource = webTarget.proxy(HawkbitSoftwareModulesResource.class); softwareModuleTypesResource = webTarget.proxy(HawkbitSoftwareModuleTypesResource.class); + rolloutsResource = webTarget.proxy(HawkbitRolloutsResource.class); + targetFiltersResource = webTarget.proxy(HawkbitTargetFiltersResource.class); // Artifact upload uses raw multipart forwarding because Hawkbit expects // multipart/form-data for this endpoint. diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java new file mode 100644 index 0000000..06e4af8 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java @@ -0,0 +1,101 @@ +package org.openremote.extension.hawkbit.manager.firmware; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import org.openremote.container.timer.TimerService; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.manager.web.ManagerWebResource; +import org.openremote.extension.hawkbit.model.firmware.FirmwareAutoAssignRequest; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQueries; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQuery; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQueryRequest; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterResource; +import org.openremote.model.http.RequestParams; + +public class FirmwareTargetFilterResourceImpl extends ManagerWebResource + implements FirmwareTargetFilterResource { + + protected final FirmwareService firmwareService; + + public FirmwareTargetFilterResourceImpl(TimerService timerService, ManagerIdentityService identityService, + FirmwareService firmwareService) { + super(timerService, identityService); + this.firmwareService = firmwareService; + } + + @Override + public FirmwareTargetFilterQueries getTargetFilters(RequestParams requestParams, Integer offset, Integer limit) { + try { + return firmwareService.targetFiltersResource.getTargetFilters(offset, limit); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware target filters", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareTargetFilterQuery getTargetFilter(RequestParams requestParams, Long id) { + try { + return firmwareService.targetFiltersResource.get(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve firmware target filter '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareTargetFilterQuery createTargetFilter(RequestParams requestParams, + FirmwareTargetFilterQueryRequest filter) { + try { + return firmwareService.targetFiltersResource.create(filter); + } catch (Exception e) { + throw new WebApplicationException("Failed to create firmware target filter", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public void deleteTargetFilter(RequestParams requestParams, Long id) { + try { + firmwareService.targetFiltersResource.delete(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to delete firmware target filter '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareDistributionSet getAutoAssignDS(RequestParams requestParams, Long id) { + try { + return firmwareService.targetFiltersResource.getAutoAssignDS(id); + } catch (Exception e) { + throw new WebApplicationException( + "Failed to retrieve auto assign distribution set for filter '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public FirmwareTargetFilterQuery setAutoAssignDS(RequestParams requestParams, Long id, + FirmwareAutoAssignRequest request) { + try { + return firmwareService.targetFiltersResource.setAutoAssignDS(id, request); + } catch (Exception e) { + throw new WebApplicationException( + "Failed to set auto assign distribution set for filter '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + + @Override + public void deleteAutoAssignDS(RequestParams requestParams, Long id) { + try { + firmwareService.targetFiltersResource.deleteAutoAssignDS(id); + } catch (Exception e) { + throw new WebApplicationException( + "Failed to remove auto assign distribution set from filter '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java new file mode 100644 index 0000000..3d88034 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java @@ -0,0 +1,66 @@ +package org.openremote.extension.hawkbit.manager.hawkbit; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRollout; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutGroup; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutGroups; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutRequest; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRollouts; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Path("rollouts") +public interface HawkbitRolloutsResource { + + String APPLICATION_HAL_JSON = "application/hal+json"; + + @GET + @Produces(APPLICATION_JSON) + FirmwareRollouts getRollouts(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit, + @QueryParam("representation") String representation); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + FirmwareRollout get(@PathParam("id") Long id); + + @POST + @Consumes(APPLICATION_HAL_JSON) + @Produces(APPLICATION_HAL_JSON) + FirmwareRollout create(FirmwareRolloutRequest rollout); + + @DELETE + @Path("{id}") + void delete(@PathParam("id") Long id); + + @POST + @Path("{id}/start") + @Produces(APPLICATION_HAL_JSON) + FirmwareRollout start(@PathParam("id") Long id); + + @POST + @Path("{id}/pause") + void pause(@PathParam("id") Long id); + + @GET + @Path("{id}/deploygroups") + @Produces(APPLICATION_JSON) + FirmwareRolloutGroups getRolloutGroups(@PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit, + @QueryParam("representation") String representation); + + @GET + @Path("{id}/deploygroups/{groupId}") + @Produces(APPLICATION_JSON) + FirmwareRolloutGroup getRolloutGroup(@PathParam("id") Long id, + @PathParam("groupId") Long groupId); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java new file mode 100644 index 0000000..01bbcf7 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java @@ -0,0 +1,58 @@ +package org.openremote.extension.hawkbit.manager.hawkbit; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import org.openremote.extension.hawkbit.model.firmware.FirmwareAutoAssignRequest; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQueries; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQuery; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQueryRequest; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Path("targetfilters") +public interface HawkbitTargetFiltersResource { + + String APPLICATION_HAL_JSON = "application/hal+json"; + + @GET + @Produces(APPLICATION_JSON) + FirmwareTargetFilterQueries getTargetFilters(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{filterId}") + @Produces(APPLICATION_JSON) + FirmwareTargetFilterQuery get(@PathParam("filterId") Long filterId); + + @POST + @Consumes(APPLICATION_HAL_JSON) + @Produces(APPLICATION_HAL_JSON) + FirmwareTargetFilterQuery create(FirmwareTargetFilterQueryRequest filter); + + @DELETE + @Path("{filterId}") + void delete(@PathParam("filterId") Long filterId); + + @GET + @Path("{filterId}/autoAssignDS") + @Produces(APPLICATION_JSON) + FirmwareDistributionSet getAutoAssignDS(@PathParam("filterId") Long filterId); + + @POST + @Path("{filterId}/autoAssignDS") + @Consumes(APPLICATION_HAL_JSON) + @Produces(APPLICATION_HAL_JSON) + FirmwareTargetFilterQuery setAutoAssignDS(@PathParam("filterId") Long filterId, + FirmwareAutoAssignRequest request); + + @DELETE + @Path("{filterId}/autoAssignDS") + void deleteAutoAssignDS(@PathParam("filterId") Long filterId); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java new file mode 100644 index 0000000..fd3cdb6 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java @@ -0,0 +1,52 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareAutoAssignRequest { + protected Long id; + protected String type; + protected Integer weight; + protected Boolean confirmationRequired; + + @JsonCreator + public FirmwareAutoAssignRequest() { + } + + public Long getId() { + return id; + } + + public FirmwareAutoAssignRequest setId(Long id) { + this.id = id; + return this; + } + + public String getType() { + return type; + } + + public FirmwareAutoAssignRequest setType(String type) { + this.type = type; + return this; + } + + public Integer getWeight() { + return weight; + } + + public FirmwareAutoAssignRequest setWeight(Integer weight) { + this.weight = weight; + return this; + } + + public Boolean getConfirmationRequired() { + return confirmationRequired; + } + + public FirmwareAutoAssignRequest setConfirmationRequired(Boolean confirmationRequired) { + this.confirmationRequired = confirmationRequired; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java new file mode 100644 index 0000000..491c661 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java @@ -0,0 +1,244 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.Map; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareRollout { + protected Long id; + protected String name; + protected String description; + protected String targetFilterQuery; + protected Long distributionSetId; + protected String status; + protected Long totalTargets; + protected Map totalTargetsPerStatus; + protected Integer totalGroups; + protected Long startAt; + protected Long forcetime; + protected Boolean deleted; + protected String type; + protected String createdBy; + protected Long createdAt; + protected String lastModifiedBy; + protected Long lastModifiedAt; + protected Integer weight; + protected Boolean confirmationRequired; + protected FirmwareRolloutCondition successCondition; + protected FirmwareRolloutAction successAction; + protected FirmwareRolloutCondition errorCondition; + protected FirmwareRolloutAction errorAction; + + @JsonCreator + protected FirmwareRollout() { + } + + public Long getId() { + return id; + } + + public FirmwareRollout setId(Long id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public FirmwareRollout setName(String name) { + this.name = name; + return this; + } + + public String getDescription() { + return description; + } + + public FirmwareRollout setDescription(String description) { + this.description = description; + return this; + } + + public String getTargetFilterQuery() { + return targetFilterQuery; + } + + public FirmwareRollout setTargetFilterQuery(String targetFilterQuery) { + this.targetFilterQuery = targetFilterQuery; + return this; + } + + public Long getDistributionSetId() { + return distributionSetId; + } + + public FirmwareRollout setDistributionSetId(Long distributionSetId) { + this.distributionSetId = distributionSetId; + return this; + } + + public String getStatus() { + return status; + } + + public FirmwareRollout setStatus(String status) { + this.status = status; + return this; + } + + public Long getTotalTargets() { + return totalTargets; + } + + public FirmwareRollout setTotalTargets(Long totalTargets) { + this.totalTargets = totalTargets; + return this; + } + + public Map getTotalTargetsPerStatus() { + return totalTargetsPerStatus; + } + + public FirmwareRollout setTotalTargetsPerStatus(Map totalTargetsPerStatus) { + this.totalTargetsPerStatus = totalTargetsPerStatus; + return this; + } + + public Integer getTotalGroups() { + return totalGroups; + } + + public FirmwareRollout setTotalGroups(Integer totalGroups) { + this.totalGroups = totalGroups; + return this; + } + + public Long getStartAt() { + return startAt; + } + + public FirmwareRollout setStartAt(Long startAt) { + this.startAt = startAt; + return this; + } + + public Long getForcetime() { + return forcetime; + } + + public FirmwareRollout setForcetime(Long forcetime) { + this.forcetime = forcetime; + return this; + } + + public Boolean getDeleted() { + return deleted; + } + + public FirmwareRollout setDeleted(Boolean deleted) { + this.deleted = deleted; + return this; + } + + public String getType() { + return type; + } + + public FirmwareRollout setType(String type) { + this.type = type; + return this; + } + + public String getCreatedBy() { + return createdBy; + } + + public FirmwareRollout setCreatedBy(String createdBy) { + this.createdBy = createdBy; + return this; + } + + public Long getCreatedAt() { + return createdAt; + } + + public FirmwareRollout setCreatedAt(Long createdAt) { + this.createdAt = createdAt; + return this; + } + + public String getLastModifiedBy() { + return lastModifiedBy; + } + + public FirmwareRollout setLastModifiedBy(String lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + return this; + } + + public Long getLastModifiedAt() { + return lastModifiedAt; + } + + public FirmwareRollout setLastModifiedAt(Long lastModifiedAt) { + this.lastModifiedAt = lastModifiedAt; + return this; + } + + public Integer getWeight() { + return weight; + } + + public FirmwareRollout setWeight(Integer weight) { + this.weight = weight; + return this; + } + + public Boolean getConfirmationRequired() { + return confirmationRequired; + } + + public FirmwareRollout setConfirmationRequired(Boolean confirmationRequired) { + this.confirmationRequired = confirmationRequired; + return this; + } + + public FirmwareRolloutCondition getSuccessCondition() { + return successCondition; + } + + public FirmwareRollout setSuccessCondition(FirmwareRolloutCondition successCondition) { + this.successCondition = successCondition; + return this; + } + + public FirmwareRolloutAction getSuccessAction() { + return successAction; + } + + public FirmwareRollout setSuccessAction(FirmwareRolloutAction successAction) { + this.successAction = successAction; + return this; + } + + public FirmwareRolloutCondition getErrorCondition() { + return errorCondition; + } + + public FirmwareRollout setErrorCondition(FirmwareRolloutCondition errorCondition) { + this.errorCondition = errorCondition; + return this; + } + + public FirmwareRolloutAction getErrorAction() { + return errorAction; + } + + public FirmwareRollout setErrorAction(FirmwareRolloutAction errorAction) { + this.errorAction = errorAction; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java new file mode 100644 index 0000000..5990f97 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java @@ -0,0 +1,32 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareRolloutAction { + protected String action; + protected String expression; + + @JsonCreator + protected FirmwareRolloutAction() { + } + + public String getAction() { + return action; + } + + public FirmwareRolloutAction setAction(String action) { + this.action = action; + return this; + } + + public String getExpression() { + return expression; + } + + public FirmwareRolloutAction setExpression(String expression) { + this.expression = expression; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java new file mode 100644 index 0000000..d9f766d --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java @@ -0,0 +1,32 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareRolloutCondition { + protected String condition; + protected String expression; + + @JsonCreator + protected FirmwareRolloutCondition() { + } + + public String getCondition() { + return condition; + } + + public FirmwareRolloutCondition setCondition(String condition) { + this.condition = condition; + return this; + } + + public String getExpression() { + return expression; + } + + public FirmwareRolloutCondition setExpression(String expression) { + this.expression = expression; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java new file mode 100644 index 0000000..521c9a4 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java @@ -0,0 +1,144 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.Map; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareRolloutGroup { + protected Long id; + protected String name; + protected String description; + protected FirmwareRolloutCondition successCondition; + protected FirmwareRolloutAction successAction; + protected FirmwareRolloutCondition errorCondition; + protected FirmwareRolloutAction errorAction; + protected String targetFilterQuery; + protected Integer targetPercentage; + protected Boolean confirmationRequired; + protected String status; + protected Long totalTargets; + protected Map totalTargetsPerStatus; + + @JsonCreator + protected FirmwareRolloutGroup() { + } + + public Long getId() { + return id; + } + + public FirmwareRolloutGroup setId(Long id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public FirmwareRolloutGroup setName(String name) { + this.name = name; + return this; + } + + public String getDescription() { + return description; + } + + public FirmwareRolloutGroup setDescription(String description) { + this.description = description; + return this; + } + + public FirmwareRolloutCondition getSuccessCondition() { + return successCondition; + } + + public FirmwareRolloutGroup setSuccessCondition(FirmwareRolloutCondition successCondition) { + this.successCondition = successCondition; + return this; + } + + public FirmwareRolloutAction getSuccessAction() { + return successAction; + } + + public FirmwareRolloutGroup setSuccessAction(FirmwareRolloutAction successAction) { + this.successAction = successAction; + return this; + } + + public FirmwareRolloutCondition getErrorCondition() { + return errorCondition; + } + + public FirmwareRolloutGroup setErrorCondition(FirmwareRolloutCondition errorCondition) { + this.errorCondition = errorCondition; + return this; + } + + public FirmwareRolloutAction getErrorAction() { + return errorAction; + } + + public FirmwareRolloutGroup setErrorAction(FirmwareRolloutAction errorAction) { + this.errorAction = errorAction; + return this; + } + + public String getTargetFilterQuery() { + return targetFilterQuery; + } + + public FirmwareRolloutGroup setTargetFilterQuery(String targetFilterQuery) { + this.targetFilterQuery = targetFilterQuery; + return this; + } + + public Integer getTargetPercentage() { + return targetPercentage; + } + + public FirmwareRolloutGroup setTargetPercentage(Integer targetPercentage) { + this.targetPercentage = targetPercentage; + return this; + } + + public Boolean getConfirmationRequired() { + return confirmationRequired; + } + + public FirmwareRolloutGroup setConfirmationRequired(Boolean confirmationRequired) { + this.confirmationRequired = confirmationRequired; + return this; + } + + public String getStatus() { + return status; + } + + public FirmwareRolloutGroup setStatus(String status) { + this.status = status; + return this; + } + + public Long getTotalTargets() { + return totalTargets; + } + + public FirmwareRolloutGroup setTotalTargets(Long totalTargets) { + this.totalTargets = totalTargets; + return this; + } + + public Map getTotalTargetsPerStatus() { + return totalTargetsPerStatus; + } + + public FirmwareRolloutGroup setTotalTargetsPerStatus(Map totalTargetsPerStatus) { + this.totalTargetsPerStatus = totalTargetsPerStatus; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java new file mode 100644 index 0000000..beecc57 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java @@ -0,0 +1,44 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareRolloutGroups { + protected List content; + protected int total; + protected int size; + + @JsonCreator + protected FirmwareRolloutGroups() { + } + + public List getContent() { + return content; + } + + public FirmwareRolloutGroups setContent(List content) { + this.content = content; + return this; + } + + public int getTotal() { + return total; + } + + public FirmwareRolloutGroups setTotal(int total) { + this.total = total; + return this; + } + + public int getSize() { + return size; + } + + public FirmwareRolloutGroups setSize(int size) { + this.size = size; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java new file mode 100644 index 0000000..8dbd003 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java @@ -0,0 +1,152 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareRolloutRequest { + protected String name; + protected String description; + protected String targetFilterQuery; + protected Long distributionSetId; + protected Integer amountGroups; + protected Long forcetime; + protected Long startAt; + protected Integer weight; + protected String type; + protected FirmwareRolloutCondition successCondition; + protected FirmwareRolloutAction successAction; + protected FirmwareRolloutCondition errorCondition; + protected FirmwareRolloutAction errorAction; + protected Boolean confirmationRequired; + + @JsonCreator + public FirmwareRolloutRequest() { + } + + public String getName() { + return name; + } + + public FirmwareRolloutRequest setName(String name) { + this.name = name; + return this; + } + + public String getDescription() { + return description; + } + + public FirmwareRolloutRequest setDescription(String description) { + this.description = description; + return this; + } + + public String getTargetFilterQuery() { + return targetFilterQuery; + } + + public FirmwareRolloutRequest setTargetFilterQuery(String targetFilterQuery) { + this.targetFilterQuery = targetFilterQuery; + return this; + } + + public Long getDistributionSetId() { + return distributionSetId; + } + + public FirmwareRolloutRequest setDistributionSetId(Long distributionSetId) { + this.distributionSetId = distributionSetId; + return this; + } + + public Integer getAmountGroups() { + return amountGroups; + } + + public FirmwareRolloutRequest setAmountGroups(Integer amountGroups) { + this.amountGroups = amountGroups; + return this; + } + + public Long getForcetime() { + return forcetime; + } + + public FirmwareRolloutRequest setForcetime(Long forcetime) { + this.forcetime = forcetime; + return this; + } + + public Long getStartAt() { + return startAt; + } + + public FirmwareRolloutRequest setStartAt(Long startAt) { + this.startAt = startAt; + return this; + } + + public Integer getWeight() { + return weight; + } + + public FirmwareRolloutRequest setWeight(Integer weight) { + this.weight = weight; + return this; + } + + public String getType() { + return type; + } + + public FirmwareRolloutRequest setType(String type) { + this.type = type; + return this; + } + + public FirmwareRolloutCondition getSuccessCondition() { + return successCondition; + } + + public FirmwareRolloutRequest setSuccessCondition(FirmwareRolloutCondition successCondition) { + this.successCondition = successCondition; + return this; + } + + public FirmwareRolloutAction getSuccessAction() { + return successAction; + } + + public FirmwareRolloutRequest setSuccessAction(FirmwareRolloutAction successAction) { + this.successAction = successAction; + return this; + } + + public FirmwareRolloutCondition getErrorCondition() { + return errorCondition; + } + + public FirmwareRolloutRequest setErrorCondition(FirmwareRolloutCondition errorCondition) { + this.errorCondition = errorCondition; + return this; + } + + public FirmwareRolloutAction getErrorAction() { + return errorAction; + } + + public FirmwareRolloutRequest setErrorAction(FirmwareRolloutAction errorAction) { + this.errorAction = errorAction; + return this; + } + + public Boolean getConfirmationRequired() { + return confirmationRequired; + } + + public FirmwareRolloutRequest setConfirmationRequired(Boolean confirmationRequired) { + this.confirmationRequired = confirmationRequired; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java new file mode 100644 index 0000000..5f5e32e --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java @@ -0,0 +1,81 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.security.RolesAllowed; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; + +import org.openremote.model.Constants; +import org.openremote.model.http.RequestParams; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Tag(name = "Firmware Rollouts", description = "Management of firmware rollouts") +@Path("firmware/rollout") +public interface FirmwareRolloutResource { + + @GET + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareRollouts getRollouts(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareRollout getRollout(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); + + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + FirmwareRollout createRollout(@BeanParam RequestParams requestParams, + FirmwareRolloutRequest rollout); + + @DELETE + @Path("{id}") + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + void deleteRollout(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); + + @POST + @Path("{id}/start") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + FirmwareRollout startRollout(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); + + @POST + @Path("{id}/pause") + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + void pauseRollout(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); + + @GET + @Path("{id}/deploygroups") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareRolloutGroups getRolloutGroups(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}/deploygroups/{groupId}") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareRolloutGroup getRolloutGroup(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + @PathParam("groupId") Long groupId); +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java new file mode 100644 index 0000000..0868694 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java @@ -0,0 +1,44 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareRollouts { + protected List content; + protected int total; + protected int size; + + @JsonCreator + protected FirmwareRollouts() { + } + + public List getContent() { + return content; + } + + public FirmwareRollouts setContent(List content) { + this.content = content; + return this; + } + + public int getTotal() { + return total; + } + + public FirmwareRollouts setTotal(int total) { + this.total = total; + return this; + } + + public int getSize() { + return size; + } + + public FirmwareRollouts setSize(int size) { + this.size = size; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java new file mode 100644 index 0000000..ea28ac0 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java @@ -0,0 +1,44 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareTargetFilterQueries { + protected List content; + protected int total; + protected int size; + + @JsonCreator + protected FirmwareTargetFilterQueries() { + } + + public List getContent() { + return content; + } + + public FirmwareTargetFilterQueries setContent(List content) { + this.content = content; + return this; + } + + public int getTotal() { + return total; + } + + public FirmwareTargetFilterQueries setTotal(int total) { + this.total = total; + return this; + } + + public int getSize() { + return size; + } + + public FirmwareTargetFilterQueries setSize(int size) { + this.size = size; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java new file mode 100644 index 0000000..13e65b3 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java @@ -0,0 +1,82 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareTargetFilterQuery { + protected Long id; + protected String name; + protected String query; + protected Long autoAssignDistributionSet; + protected String autoAssignActionType; + protected Integer autoAssignWeight; + protected Boolean confirmationRequired; + + @JsonCreator + protected FirmwareTargetFilterQuery() { + } + + public Long getId() { + return id; + } + + public FirmwareTargetFilterQuery setId(Long id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public FirmwareTargetFilterQuery setName(String name) { + this.name = name; + return this; + } + + public String getQuery() { + return query; + } + + public FirmwareTargetFilterQuery setQuery(String query) { + this.query = query; + return this; + } + + public Long getAutoAssignDistributionSet() { + return autoAssignDistributionSet; + } + + public FirmwareTargetFilterQuery setAutoAssignDistributionSet(Long autoAssignDistributionSet) { + this.autoAssignDistributionSet = autoAssignDistributionSet; + return this; + } + + public String getAutoAssignActionType() { + return autoAssignActionType; + } + + public FirmwareTargetFilterQuery setAutoAssignActionType(String autoAssignActionType) { + this.autoAssignActionType = autoAssignActionType; + return this; + } + + public Integer getAutoAssignWeight() { + return autoAssignWeight; + } + + public FirmwareTargetFilterQuery setAutoAssignWeight(Integer autoAssignWeight) { + this.autoAssignWeight = autoAssignWeight; + return this; + } + + public Boolean getConfirmationRequired() { + return confirmationRequired; + } + + public FirmwareTargetFilterQuery setConfirmationRequired(Boolean confirmationRequired) { + this.confirmationRequired = confirmationRequired; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java new file mode 100644 index 0000000..ac84596 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java @@ -0,0 +1,32 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareTargetFilterQueryRequest { + protected String name; + protected String query; + + @JsonCreator + public FirmwareTargetFilterQueryRequest() { + } + + public String getName() { + return name; + } + + public FirmwareTargetFilterQueryRequest setName(String name) { + this.name = name; + return this; + } + + public String getQuery() { + return query; + } + + public FirmwareTargetFilterQueryRequest setQuery(String query) { + this.query = query; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java new file mode 100644 index 0000000..3c35498 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java @@ -0,0 +1,72 @@ +package org.openremote.extension.hawkbit.model.firmware; + +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.security.RolesAllowed; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; + +import org.openremote.model.Constants; +import org.openremote.model.http.RequestParams; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Tag(name = "Firmware Target Filters", description = "Management of firmware target filter queries") +@Path("firmware/targetfilter") +public interface FirmwareTargetFilterResource { + + @GET + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareTargetFilterQueries getTargetFilters(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareTargetFilterQuery getTargetFilter(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); + + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + FirmwareTargetFilterQuery createTargetFilter(@BeanParam RequestParams requestParams, + FirmwareTargetFilterQueryRequest filter); + + @DELETE + @Path("{id}") + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + void deleteTargetFilter(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); + + @GET + @Path("{id}/autoAssignDS") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareDistributionSet getAutoAssignDS(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); + + @POST + @Path("{id}/autoAssignDS") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + FirmwareTargetFilterQuery setAutoAssignDS(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + FirmwareAutoAssignRequest request); + + @DELETE + @Path("{id}/autoAssignDS") + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + void deleteAutoAssignDS(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); +} From c3094532248986636315a9e49a0fd3f077467759 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Thu, 7 May 2026 12:41:30 +0200 Subject: [PATCH 03/18] License headers --- .../FirmwareDistributionSetResourceImpl.java | 19 +++++++++++++++++++ ...rmwareDistributionSetTypeResourceImpl.java | 19 +++++++++++++++++++ .../firmware/FirmwareRolloutResourceImpl.java | 19 +++++++++++++++++++ .../FirmwareSoftwareModuleResourceImpl.java | 19 +++++++++++++++++++ ...irmwareSoftwareModuleTypeResourceImpl.java | 19 +++++++++++++++++++ .../FirmwareTargetFilterResourceImpl.java | 19 +++++++++++++++++++ .../firmware/FirmwareTargetResourceImpl.java | 19 +++++++++++++++++++ .../hawkbit/HawkbitArtifactUploadClient.java | 19 +++++++++++++++++++ .../manager/hawkbit/HawkbitBasicAuth.java | 19 +++++++++++++++++++ .../HawkbitDistributionSetTypesResource.java | 19 +++++++++++++++++++ .../HawkbitDistributionSetsResource.java | 19 +++++++++++++++++++ .../hawkbit/HawkbitRolloutsResource.java | 19 +++++++++++++++++++ .../HawkbitSoftwareModuleTypesResource.java | 19 +++++++++++++++++++ .../HawkbitSoftwareModulesResource.java | 19 +++++++++++++++++++ .../hawkbit/HawkbitTargetFiltersResource.java | 19 +++++++++++++++++++ .../hawkbit/HawkbitTargetsResource.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareAction.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareActionLinks.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareActions.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareArtifact.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareArtifactLinks.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareArtifacts.java | 19 +++++++++++++++++++ .../firmware/FirmwareAssignedAction.java | 19 +++++++++++++++++++ .../firmware/FirmwareAutoAssignRequest.java | 19 +++++++++++++++++++ .../firmware/FirmwareDistributionSet.java | 19 +++++++++++++++++++ .../FirmwareDistributionSetAssignment.java | 19 +++++++++++++++++++ ...rmwareDistributionSetAssignmentResult.java | 19 +++++++++++++++++++ .../FirmwareDistributionSetResource.java | 19 +++++++++++++++++++ .../firmware/FirmwareDistributionSetType.java | 19 +++++++++++++++++++ .../FirmwareDistributionSetTypeResource.java | 19 +++++++++++++++++++ .../FirmwareDistributionSetTypes.java | 19 +++++++++++++++++++ .../firmware/FirmwareDistributionSets.java | 19 +++++++++++++++++++ .../hawkbit/model/firmware/FirmwareLink.java | 19 +++++++++++++++++++ .../firmware/FirmwareMaintenanceWindow.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareMetaItemType.java | 19 +++++++++++++++++++ .../model/firmware/FirmwarePollStatus.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareRollout.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareRolloutAction.java | 19 +++++++++++++++++++ .../firmware/FirmwareRolloutCondition.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareRolloutGroup.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareRolloutGroups.java | 19 +++++++++++++++++++ .../firmware/FirmwareRolloutRequest.java | 19 +++++++++++++++++++ .../firmware/FirmwareRolloutResource.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareRollouts.java | 19 +++++++++++++++++++ .../firmware/FirmwareSoftwareModule.java | 19 +++++++++++++++++++ .../FirmwareSoftwareModuleResource.java | 19 +++++++++++++++++++ .../firmware/FirmwareSoftwareModuleType.java | 19 +++++++++++++++++++ .../FirmwareSoftwareModuleTypeAssignment.java | 19 +++++++++++++++++++ .../FirmwareSoftwareModuleTypeResource.java | 19 +++++++++++++++++++ .../firmware/FirmwareSoftwareModuleTypes.java | 19 +++++++++++++++++++ .../firmware/FirmwareSoftwareModules.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareTarget.java | 19 +++++++++++++++++++ .../firmware/FirmwareTargetAssignment.java | 19 +++++++++++++++++++ .../firmware/FirmwareTargetFilterQueries.java | 19 +++++++++++++++++++ .../firmware/FirmwareTargetFilterQuery.java | 19 +++++++++++++++++++ .../FirmwareTargetFilterQueryRequest.java | 19 +++++++++++++++++++ .../FirmwareTargetFilterResource.java | 19 +++++++++++++++++++ .../firmware/FirmwareTargetResource.java | 19 +++++++++++++++++++ .../model/firmware/FirmwareTargets.java | 19 +++++++++++++++++++ 59 files changed, 1121 insertions(+) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java index cc8c59e..b76d42b 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.firmware; import jakarta.ws.rs.DELETE; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java index af1e19f..00eefc4 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.firmware; import jakarta.ws.rs.WebApplicationException; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java index 8d04248..c437a47 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.firmware; import jakarta.ws.rs.WebApplicationException; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java index 196f267..ff554dd 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.firmware; import jakarta.ws.rs.Consumes; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java index 93c3fe1..cb329f9 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.firmware; import jakarta.ws.rs.WebApplicationException; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java index 06e4af8..c779cef 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.firmware; import jakarta.ws.rs.WebApplicationException; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java index 4cdab72..372d9fe 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.firmware; import jakarta.ws.rs.WebApplicationException; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java index 38d1fa1..cfc9bf4 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.hawkbit; import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifact; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitBasicAuth.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitBasicAuth.java index 55024b5..f457aa2 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitBasicAuth.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitBasicAuth.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.hawkbit; import java.nio.charset.StandardCharsets; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java index fea245c..95b841e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.hawkbit; import jakarta.ws.rs.Consumes; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java index 55133ac..6b9963c 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.hawkbit; import jakarta.ws.rs.DELETE; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java index 3d88034..c499ca0 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.hawkbit; import jakarta.ws.rs.Consumes; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java index ebe4066..a901f7f 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.hawkbit; import jakarta.ws.rs.Consumes; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java index 01a2bb1..179e4aa 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.hawkbit; import jakarta.ws.rs.DELETE; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java index 01bbcf7..3dfb7c6 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.hawkbit; import jakarta.ws.rs.Consumes; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java index 4cc507c..ed9d9ca 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.manager.hawkbit; import jakarta.ws.rs.*; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java index 02509da..4200daf 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java index 8d5b8dc..71d0ba1 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java index f7e9585..0689df1 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java index 716edef..a0a511e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java index 9a82d40..3e737f1 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java index 093af75..7c28791 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAssignedAction.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAssignedAction.java index eb81402..739a12a 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAssignedAction.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAssignedAction.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java index fd3cdb6..5f450fc 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java index 25c3766..17dc5e5 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java index 5f521c6..b9efbac 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java index a9ecb17..898042e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java index b4eae3a..7c0a1e9 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import io.swagger.v3.oas.annotations.tags.Tag; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java index 70b04f3..21e9cc7 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java index 93b5592..6c1b2c6 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import io.swagger.v3.oas.annotations.tags.Tag; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java index 02049f0..58fa4ef 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java index 9291968..491fa18 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java index e5301dc..4166398 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java index 3176cf7..f890ac4 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java index d8ad49f..95bcae8 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import org.openremote.model.util.TsIgnore; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java index e1ecd7e..1d16e62 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java index 491c661..03c773b 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java index 5990f97..b6257b5 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java index d9f766d..1eb8323 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java index 521c9a4..24f310d 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java index beecc57..ebf6700 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java index 8dbd003..a9370d8 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java index 5f5e32e..4d9709c 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import io.swagger.v3.oas.annotations.tags.Tag; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java index 0868694..b2a2c3f 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java index 34d4b1d..85cdedf 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java index 89dc43d..3945c62 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import io.swagger.v3.oas.annotations.tags.Tag; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java index 1770bba..af8214d 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java index 8dd3f03..f7a349e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java index 8775ae2..b46dbce 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import io.swagger.v3.oas.annotations.tags.Tag; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java index fc529b0..50e6f1c 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java index d037809..fe1dec4 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java index bf6f636..b4c9984 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java index 077de5c..4ca7fd1 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java index ea28ac0..3eb27c4 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java index 13e65b3..a2e3456 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java index ac84596..f658e02 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java index 3c35498..ca5ce41 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import io.swagger.v3.oas.annotations.tags.Tag; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java index f88feec..48477d5 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import jakarta.annotation.security.RolesAllowed; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java index eecd450..f6776e9 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java @@ -1,3 +1,22 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package org.openremote.extension.hawkbit.model.firmware; import com.fasterxml.jackson.annotation.JsonCreator; From 35e7ba9474c6f5dee81c3c6f51468e68d8e7c2c1 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Mon, 11 May 2026 10:59:44 +0200 Subject: [PATCH 04/18] Add attribute to hawkBit target.metadata sync support --- .../manager/firmware/FirmwareService.java | 124 +++++++++++++++++- .../firmware/FirmwareTargetResourceImpl.java | 15 ++- .../hawkbit/HawkbitTargetsResource.java | 20 ++- .../model/firmware/FirmwareMetaItemType.java | 9 ++ .../model/firmware/FirmwareMetadata.java | 56 ++++++++ .../model/firmware/FirmwareMetadataList.java | 63 +++++++++ .../firmware/FirmwareMetadataUpdate.java | 45 +++++++ .../model/firmware/FirmwareModelProvider.java | 44 +++++++ .../firmware/FirmwareTargetResource.java | 11 +- .../org.openremote.model.AssetModelProvider | 1 + 10 files changed, 376 insertions(+), 12 deletions(-) create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadata.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataList.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataUpdate.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModelProvider.java create mode 100644 hawkbit/src/main/resources/META-INF/services/org.openremote.model.AssetModelProvider diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java index e9dc341..3830a31 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java @@ -34,6 +34,7 @@ import java.util.logging.Level; import java.util.logging.Logger; +import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.client.ClientRequestFilter; import jakarta.ws.rs.core.HttpHeaders; import org.jboss.resteasy.client.jaxrs.ResteasyClient; @@ -61,9 +62,12 @@ import org.openremote.model.asset.Asset; import org.openremote.model.asset.AssetEvent; import org.openremote.model.asset.AssetTypeInfo; +import org.openremote.model.attribute.Attribute; import org.openremote.model.attribute.AttributeEvent; +import org.openremote.model.attribute.MetaMap; import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifact; import org.openremote.extension.hawkbit.model.firmware.FirmwareMetaItemType; +import org.openremote.extension.hawkbit.model.firmware.FirmwareMetadataUpdate; import org.openremote.extension.hawkbit.model.firmware.FirmwareTarget; import org.openremote.model.syslog.SyslogCategory; import org.openremote.model.util.TextUtil; @@ -186,12 +190,18 @@ public void start(Container container) throws Exception { // multipart/form-data for this endpoint. artifactUploadClient = new HawkbitArtifactUploadClient(uri, hawkbitUsername, hawkbitPassword); - // Subscribe for asset events + // Subscribe on asset events clientEventService.addSubscription( AssetEvent.class, null, this::onAssetChange); + // Subscribe on attribute events + clientEventService.addSubscription( + AttributeEvent.class, + null, + this::onAttributeChange); + LOG.log(Level.INFO, "Firmware Service started, connected hawkBit instance: " + uri + ", for realm: " + hawkbitRealm); } @@ -209,7 +219,6 @@ public FirmwareArtifact uploadSoftwareModuleArtifact(Long softwareModuleId, Inpu } private void onAssetChange(AssetEvent assetEvent) { - // Ignore events if they are not for the configured hawkBit realm if (!Objects.equals(assetEvent.getRealm(), hawkbitRealm)) { return; @@ -219,6 +228,32 @@ private void onAssetChange(AssetEvent assetEvent) { executorService.submit(() -> handleAssetChange(assetEvent)); } + private void onAttributeChange(AttributeEvent attributeEvent) { + if (!Objects.equals(attributeEvent.getRealm(), hawkbitRealm)) + { + return; + } + + // Submit the attributeEvent to the executorService + executorService.submit(() -> handleAttributeChange(attributeEvent)); + } + + private void handleAttributeChange(AttributeEvent attributeEvent) { + if (!hasFirmwareMetadata(attributeEvent.getAssetType(), attributeEvent.getName(), attributeEvent.getMeta())) { + return; + } + + if (attributeEvent.isDeleted()) { + deleteFirmwareTargetMetadata(attributeEvent.getId(), attributeEvent.getName()); + return; + } + + attributeEvent.getValue().ifPresent(value -> syncFirmwareTargetMetadataValue( + attributeEvent.getId(), + attributeEvent.getName(), + value)); + } + private void handleAssetChange(AssetEvent assetEvent) { Asset asset = assetEvent.getAsset(); @@ -266,10 +301,87 @@ private void handleAssetChange(AssetEvent assetEvent) { if (shouldUpdateFirmwareTargetInfo) { updateFirmwareTargetInfo(assetEvent); + updateFirmwareTargetMetadata(asset); + } + } + + private void updateFirmwareTargetMetadata(Asset asset) { + String controllerId = asset.getId(); + for (Attribute attribute : asset.getAttributes().values()) { + if (!hasFirmwareMetadata(asset.getType(), attribute.getName(), attribute.getMeta())) { + continue; + } + + attribute.getValue().ifPresent(value -> + syncFirmwareTargetMetadataValue(controllerId, attribute.getName(), value)); + } + } + + private boolean hasFirmwareMetadata(String assetType, String attributeName, MetaMap meta) { + if (hasFirmwareMetadata(meta)) { + return true; + } + + if (assetType == null) { + return false; + } + + Optional assetTypeInfo = ValueUtil.getAssetInfo(assetType); + return assetTypeInfo + .map(typeInfo -> typeInfo.getAttributeDescriptors().values().stream() + .filter(attributeDescriptor -> Objects.equals(attributeDescriptor.getName(), attributeName)) + .anyMatch(attributeDescriptor -> hasFirmwareMetadata(attributeDescriptor.getMeta()))) + .orElse(false); + } + + private boolean hasFirmwareMetadata(MetaMap meta) { + return meta != null + && meta.get(FirmwareMetaItemType.FIRMWARE_METADATA) + .flatMap(metaItem -> metaItem.getValue(Boolean.class)) + .orElse(false); + } + + private void syncFirmwareTargetMetadataValue(String controllerId, String key, Object value) { + if (value == null) { + return; + } + + Optional metadataValue = ValueUtil.getStringCoerced(value); + if (metadataValue.isEmpty()) { + LOG.warning("Cannot convert firmware metadata value to string for target id=" + + controllerId + ", key=" + key); + return; + } + + updateFirmwareTargetMetadata(controllerId, key, metadataValue.get()); + } + + private void updateFirmwareTargetMetadata(String controllerId, String key, String value) { + try { + targetsResource.updateMetadata(controllerId, key, new FirmwareMetadataUpdate(value)); + LOG.fine("Updated hawkbit target metadata targetId=" + controllerId + ", key=" + key); + } catch (NotFoundException e) { + LOG.fine("hawkbit target not found for metadata sync targetId=" + + controllerId + ", key=" + key); + } catch (Exception e) { + LOG.log(Level.WARNING, "Failed to update hawkbit target metadata targetId=" + + controllerId + ", key=" + key, e); + } + } + + private void deleteFirmwareTargetMetadata(String controllerId, String key) { + try { + targetsResource.deleteMetadata(controllerId, key); + LOG.fine("Deleted hawkbit target metadata targetId=" + controllerId + ", key=" + key); + } catch (NotFoundException e) { + LOG.fine("hawkbit target metadata not found for delete targetId=" + + controllerId + ", key=" + key); + } catch (Exception e) { + LOG.log(Level.WARNING, "Failed to delete hawkbit target metadata targetId=" + + controllerId + ", key=" + key, e); } } - @SuppressWarnings({ "rawtypes" }) private Optional> getFirmwareTargetInfoDescriptor(Asset asset) { Optional assetTypeInfo = ValueUtil.getAssetInfo(asset.getType()); if (assetTypeInfo.isEmpty()) { @@ -297,7 +409,7 @@ private Optional> getFirmwareTargetInfoDescriptor(Asset asset) { @@ -318,14 +430,12 @@ private boolean createFirmwareTarget(FirmwareTarget target) { } } - private boolean deleteFirmwareTarget(String controllerId) { + private void deleteFirmwareTarget(String controllerId) { try { targetsResource.delete(controllerId); LOG.info("Deleted hawkbit target id=" + controllerId); - return true; } catch (Exception e) { LOG.log(Level.WARNING, "Failed to delete hawkbit target id=" + controllerId, e); - return false; } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java index 372d9fe..13518a8 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java @@ -28,6 +28,7 @@ import org.openremote.extension.hawkbit.model.firmware.FirmwareAction; import org.openremote.extension.hawkbit.model.firmware.FirmwareActions; import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; +import org.openremote.extension.hawkbit.model.firmware.FirmwareMetadataList; import org.openremote.extension.hawkbit.model.firmware.FirmwareTarget; import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetResource; import org.openremote.extension.hawkbit.model.firmware.FirmwareTargets; @@ -43,9 +44,9 @@ public FirmwareTargetResourceImpl(TimerService timerService, ManagerIdentityServ } @Override - public FirmwareTargets getTargets(RequestParams requestParams, Integer offset, Integer limit) { + public FirmwareTargets getTargets(RequestParams requestParams, String query, Integer offset, Integer limit) { try { - return firmwareService.targetsResource.getTargets(offset, limit); + return firmwareService.targetsResource.getTargets(query, offset, limit); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware targets", e, Response.Status.BAD_GATEWAY); } @@ -61,6 +62,16 @@ public FirmwareTarget getTarget(RequestParams requestParams, String id) { } } + @Override + public FirmwareMetadataList getMetadata(RequestParams requestParams, String id) { + try { + return firmwareService.targetsResource.getMetadata(id); + } catch (Exception e) { + throw new WebApplicationException("Failed to retrieve metadata for firmware target '" + id + "'", e, + Response.Status.BAD_GATEWAY); + } + } + @Override public FirmwareDistributionSet getAssignedDs(RequestParams requestParams, String id) { try { diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java index ed9d9ca..d820aa2 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java @@ -23,6 +23,8 @@ import org.openremote.extension.hawkbit.model.firmware.FirmwareAction; import org.openremote.extension.hawkbit.model.firmware.FirmwareActions; import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; +import org.openremote.extension.hawkbit.model.firmware.FirmwareMetadataList; +import org.openremote.extension.hawkbit.model.firmware.FirmwareMetadataUpdate; import org.openremote.extension.hawkbit.model.firmware.FirmwareTarget; import org.openremote.extension.hawkbit.model.firmware.FirmwareTargets; @@ -33,7 +35,7 @@ public interface HawkbitTargetsResource { @GET @Produces(APPLICATION_JSON) - FirmwareTargets getTargets(@QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit); + FirmwareTargets getTargets(@QueryParam("q") String query, @QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit); @POST @Consumes(APPLICATION_JSON) @@ -56,6 +58,22 @@ public interface HawkbitTargetsResource { @Path("{id}") void delete(@PathParam("id") String id); + @GET + @Path("{id}/metadata") + @Produces(APPLICATION_JSON) + FirmwareMetadataList getMetadata(@PathParam("id") String id); + + @PUT + @Path("{id}/metadata/{key}") + @Consumes(APPLICATION_JSON) + void updateMetadata(@PathParam("id") String id, + @PathParam("key") String key, + FirmwareMetadataUpdate metadata); + + @DELETE + @Path("{id}/metadata/{key}") + void deleteMetadata(@PathParam("id") String id, @PathParam("key") String key); + @GET @Path("{id}/assignedDS") @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java index 95bcae8..ebdc112 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java @@ -36,4 +36,13 @@ private FirmwareMetaItemType() { */ public static final MetaItemDescriptor FIRMWARE_TARGET = new MetaItemDescriptor<>( "firmwareTarget", ValueType.BOOLEAN); + + /** + * Can be used on any attribute to indicate that this attribute should be synced as metadata to the corresponding + * target in hawkBit, enabling hawkBit target filters on specific metadata values. + * Requires the parent asset to be synced to hawkBit via the firmwareTarget metaItem. + */ + public static final MetaItemDescriptor FIRMWARE_METADATA = new MetaItemDescriptor<>( + "firmwareMetadata", ValueType.BOOLEAN); + } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadata.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadata.java new file mode 100644 index 0000000..5ecce68 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadata.java @@ -0,0 +1,56 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareMetadata { + protected String key; + protected String value; + + @JsonCreator + protected FirmwareMetadata() { + } + + public FirmwareMetadata(String key, String value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + public FirmwareMetadata setKey(String key) { + this.key = key; + return this; + } + + public String getValue() { + return value; + } + + public FirmwareMetadata setValue(String value) { + this.value = value; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataList.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataList.java new file mode 100644 index 0000000..5e6914f --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataList.java @@ -0,0 +1,63 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareMetadataList { + protected List content; + protected int total; + protected int size; + + @JsonCreator + protected FirmwareMetadataList() { + } + + public List getContent() { + return content; + } + + public FirmwareMetadataList setContent(List content) { + this.content = content; + return this; + } + + public int getTotal() { + return total; + } + + public FirmwareMetadataList setTotal(int total) { + this.total = total; + return this; + } + + public int getSize() { + return size; + } + + public FirmwareMetadataList setSize(int size) { + this.size = size; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataUpdate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataUpdate.java new file mode 100644 index 0000000..87ed414 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataUpdate.java @@ -0,0 +1,45 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class FirmwareMetadataUpdate { + protected String value; + + @JsonCreator + protected FirmwareMetadataUpdate() { + } + + public FirmwareMetadataUpdate(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public FirmwareMetadataUpdate setValue(String value) { + this.value = value; + return this; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModelProvider.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModelProvider.java new file mode 100644 index 0000000..4d9b449 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModelProvider.java @@ -0,0 +1,44 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import org.openremote.model.AssetModelProvider; +import org.openremote.model.asset.Asset; +import org.openremote.model.value.MetaItemDescriptor; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public class FirmwareModelProvider implements AssetModelProvider { + + @Override + public boolean useAutoScan() { + return false; + } + + @Override + public Map>> getMetaItemDescriptors() { + Collection> descriptors = List.of( + FirmwareMetaItemType.FIRMWARE_TARGET, + FirmwareMetaItemType.FIRMWARE_METADATA); + return Map.of(Asset.class.getSimpleName(), descriptors); + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java index 48477d5..2d8800b 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java @@ -42,8 +42,9 @@ public interface FirmwareTargetResource { @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) FirmwareTargets getTargets(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("q") String query, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @@ -51,6 +52,12 @@ FirmwareTargets getTargets(@BeanParam RequestParams requestParams, @RolesAllowed({Constants.READ_ADMIN_ROLE}) FirmwareTarget getTarget(@BeanParam RequestParams requestParams, @PathParam("id") String id); + @GET + @Path("{id}/metadata") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + FirmwareMetadataList getMetadata(@BeanParam RequestParams requestParams, @PathParam("id") String id); + @GET @Path("{id}/assignedDS") @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/resources/META-INF/services/org.openremote.model.AssetModelProvider b/hawkbit/src/main/resources/META-INF/services/org.openremote.model.AssetModelProvider new file mode 100644 index 0000000..cd197f1 --- /dev/null +++ b/hawkbit/src/main/resources/META-INF/services/org.openremote.model.AssetModelProvider @@ -0,0 +1 @@ +org.openremote.extension.hawkbit.model.firmware.FirmwareModelProvider From 4f79714ebde1cfa69c66535558b4084ca1dc130f Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Mon, 11 May 2026 11:54:10 +0200 Subject: [PATCH 05/18] Add documentation, with compose and haproxy examples. --- hawkbit/README.md | 194 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 hawkbit/README.md diff --git a/hawkbit/README.md b/hawkbit/README.md new file mode 100644 index 0000000..875eb10 --- /dev/null +++ b/hawkbit/README.md @@ -0,0 +1,194 @@ +# hawkBit + +## Introduction + +[hawkBit](https://www.eclipse.org/hawkbit/) is a software update server for connected devices. + +This extension connects OpenRemote Manager to the hawkBit Management API, exposes firmware endpoints in OpenRemote, and syncs selected assets as hawkBit targets. + +## Prerequisites + +You need: + +1. A hawkBit instance reachable from OpenRemote Manager +2. Management API credentials for hawkBit +3. An OpenRemote realm that should be synced with hawkBit +4. Assets configured with the firmware meta items described below + +## Configuration + +The following environment variables can be set on the OpenRemote manager: + +| Variable | Required | Description | +|---|---|---| +| `HAWKBIT_MANAGEMENT_API_URL` | No | hawkBit Management API URL (default: `http://localhost:8083/hawkbit/rest/v1`) | +| `HAWKBIT_USERNAME` | No | hawkBit Management API username (default: `hawkbit`) | +| `HAWKBIT_PASSWORD` | No | hawkBit Management API password (default: `hawkbit`) | +| `HAWKBIT_REALM` | No | OpenRemote realm to sync with hawkBit (default: `master`) | + +### Docker Compose Example + +hawkBit can be started with a separate PostgreSQL database and persistent artifact storage: + +```yaml +volumes: + hawkbitdb-data: + hawkbit-artifact-data: + +services: + hawkbitdb: + image: openremote/postgresql:${POSTGRESQL_VERSION:-latest-slim} + restart: always + environment: + POSTGRES_DB: hawkbit + POSTGRES_USER: ${HAWKBIT_DB_USER:-postgres} + POSTGRES_PASSWORD: ${HAWKBIT_DB_PASSWORD:-postgres} + volumes: + - hawkbitdb-data:/var/lib/postgresql/data + + hawkbit: + image: openremote/hawkbit-update-server:develop + restart: always + depends_on: + hawkbitdb: + condition: service_healthy + healthcheck: + interval: 3s + timeout: 3s + start_period: 3s + retries: 100 + test: ["CMD", "curl", "--fail", "--silent", "http://localhost:8080/hawkbit"] + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://hawkbitdb:5432/hawkbit + - SPRING_DATASOURCE_USERNAME=${HAWKBIT_DB_USER:-postgres} + - SPRING_DATASOURCE_PASSWORD=${HAWKBIT_DB_PASSWORD:-postgres} + - SPRING_JPA_DATABASE=POSTGRESQL + - SPRING_DATASOURCE_DRIVER_CLASS_NAME=org.postgresql.Driver + - HAWKBIT_DMF_RABBITMQ_ENABLED=false + - HAWKBIT_ARTIFACT_URL_PROTOCOLS_DOWNLOAD_HTTP_PORT=${HTTPS_FORWARDED_PORT:-443} + - HAWKBIT_ARTIFACT_URL_PROTOCOLS_DOWNLOAD_HTTP_PROTOCOL=https + - HAWKBIT_ARTIFACT_URL_PROTOCOLS_DOWNLOAD_HTTP_REF={protocol}://{hostnameRequest}:{port}$${server.servlet.context-path}/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName} + - HAWKBIT_SERVER_DDI_SECURITY_AUTHENTICATION_TARGETTOKEN_ENABLED=true + - SERVER_USE_FORWARD_HEADERS=true + - SERVER_FORWARD_HEADERS_STRATEGY=NATIVE + - SERVER_SERVLET_CONTEXT_PATH=/hawkbit + - HAWKBIT_SECURITY_USER_ADMIN_TENANT=#{null} + - HAWKBIT_SECURITY_USER_ADMIN_PASSWORD=#{null} + - HAWKBIT_SECURITY_USER_ADMIN_ROLES=#{null} + - HAWKBIT_SECURITY_USER_HAWKBIT_TENANT=DEFAULT + - HAWKBIT_SECURITY_USER_HAWKBIT_PASSWORD={noop}${HAWKBIT_PASSWORD:?HAWKBIT_PASSWORD must be set} + - HAWKBIT_SECURITY_USER_HAWKBIT_ROLES=TENANT_ADMIN + volumes: + - hawkbit-artifact-data:/opt/hawkbit/artifactrepo + expose: + - "8080" +``` + +Set the matching Manager environment variables: + +```env +HAWKBIT_MANAGEMENT_API_URL=http://hawkbit:8080/hawkbit/rest/v1 +HAWKBIT_PASSWORD= +``` + +### HAProxy Example + +When hawkBit is behind the OpenRemote proxy, only expose the DDI controller API publicly. OpenRemote Manager uses the Management API over the internal Docker network. + +Add the hawkBit ACLs in the `https` frontend before the final `use_backend manager_backend` rule: + +```haproxy + # hawkBit DDI API for device polling and artifact downloads + acl hawkbit_management_api path_beg /hawkbit/rest/ + acl hawkbit_ddi path_reg ^/hawkbit/[^/]+/controller/v1(/|$) + + http-request deny deny_status 404 if hawkbit_management_api + use_backend hawkbit_backend if hawkbit_ddi +``` + +Add the hawkBit backend: + +```haproxy +backend hawkbit_backend + server hawkbit "${HAWKBIT_HOST}":"${HAWKBIT_PORT}" resolvers docker_resolver +``` + +With the Compose example above, set the proxy environment variables: + +```env +HAWKBIT_HOST=hawkbit +HAWKBIT_PORT=8080 +``` + +The public DDI URL uses `/hawkbit/{tenant}/controller/v1/...`. The Management API at `/hawkbit/rest/v1/...` stays internal. + +## Asset Usage + +### Firmware Targets + +To sync an OpenRemote asset as a hawkBit target, add the `firmwareTarget` meta item to one attribute of the asset. + +When the asset is created or updated in the configured realm, the extension creates a hawkBit target using the OpenRemote asset ID as the hawkBit controller ID. The target info attribute is updated with the `controllerId` and `securityToken` returned by hawkBit. + +When the asset is deleted, the matching hawkBit target is deleted. + +### Firmware Metadata + +To sync an attribute value as hawkBit target metadata, add the `firmwareMetadata` meta item to the attribute. + +Metadata values are converted to strings. The OpenRemote attribute name is used as the hawkBit metadata key. Deleting the attribute removes the metadata entry in hawkBit. + +The parent asset must also be synced as a firmware target with `firmwareTarget`. + +## Firmware API + +OpenRemote Manager exposes endpoints that forward to the configured hawkBit instance. + +| Resource | Path | Functionality | +|---|---|---| +| Firmware targets | `firmware/target` | List targets, get target details, metadata, assigned and installed distribution sets, actions | +| Software module types | `firmware/softwaremoduletype` | Create, list, get and delete software module types | +| Software modules | `firmware/softwaremodule` | Create, list, get and delete software modules, list and upload artifacts | +| Distribution set types | `firmware/distributionsettype` | Create, list, get and delete distribution set types, list module type assignments | +| Distribution sets | `firmware/distributionset` | Create, list, get, assign to targets and delete distribution sets | +| Target filters | `firmware/targetfilter` | Create, list, get and delete target filters, manage auto assignment | +| Rollouts | `firmware/rollout` | Create, list, get, start, pause and delete rollouts, list rollout groups | + +Read endpoints require the OpenRemote read admin role. Write endpoints require the write admin role. + +## Data Flow + +```mermaid +sequenceDiagram + participant OR as OpenRemote + participant HB as hawkBit + participant Device as Device + + OR->>HB: Create target from asset + HB-->>OR: Target controller ID and security token + OR->>HB: Sync selected asset attributes as metadata + OR->>HB: Create modules, distribution sets or rollouts + Device->>HB: Poll for assigned firmware actions +``` + +## Components + +``` +manager/firmware/ + FirmwareService.java Starts the integration, syncs assets and registers API resources + FirmwareTargetResourceImpl.java Proxies target and action requests to hawkBit + FirmwareSoftwareModuleResourceImpl.java Proxies software module requests and artifact uploads + FirmwareDistributionSetResourceImpl.java Proxies distribution set requests and target assignment + FirmwareRolloutResourceImpl.java Proxies rollout requests + +manager/hawkbit/ + HawkbitTargetsResource.java RESTEasy client proxy for hawkBit targets + HawkbitSoftwareModulesResource.java RESTEasy client proxy for software modules + HawkbitDistributionSetsResource.java RESTEasy client proxy for distribution sets + HawkbitRolloutsResource.java RESTEasy client proxy for rollouts + HawkbitArtifactUploadClient.java Multipart artifact upload client + +model/firmware/ + FirmwareMetaItemType.java Defines firmwareTarget and firmwareMetadata meta items + FirmwareModelProvider.java Registers firmware meta items in the OpenRemote model +``` From 3ece36e23332b8179f1512e6a8efb12afd411335 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Wed, 13 May 2026 15:28:23 +0200 Subject: [PATCH 06/18] Refactor into a proxy style, remainder dto's changed to records. --- .../FirmwareDistributionSetResourceImpl.java | 50 +--- ...rmwareDistributionSetTypeResourceImpl.java | 38 +-- .../firmware/FirmwareRolloutResourceImpl.java | 33 +-- .../manager/firmware/FirmwareService.java | 49 +++- .../FirmwareSoftwareModuleResourceImpl.java | 33 +-- ...irmwareSoftwareModuleTypeResourceImpl.java | 23 +- .../FirmwareTargetFilterResourceImpl.java | 30 +- .../firmware/FirmwareTargetResourceImpl.java | 34 +-- .../manager/firmware/HawkbitResponse.java | 196 +++++++++++++ .../hawkbit/HawkbitArtifactUploadClient.java | 20 +- .../HawkbitDistributionSetTypesResource.java | 28 +- .../HawkbitDistributionSetsResource.java | 23 +- .../hawkbit/HawkbitMediaType.java} | 23 +- .../hawkbit/HawkbitRolloutsResource.java | 34 +-- .../HawkbitSoftwareModuleTypesResource.java | 15 +- .../HawkbitSoftwareModulesResource.java | 18 +- .../hawkbit/HawkbitTargetFiltersResource.java | 24 +- .../hawkbit/HawkbitTargetsResource.java | 33 +-- .../model/firmware/FirmwareAction.java | 176 ------------ .../model/firmware/FirmwareActionLinks.java | 41 --- .../model/firmware/FirmwareActions.java | 63 ----- .../model/firmware/FirmwareArtifact.java | 83 ------ .../model/firmware/FirmwareArtifactLinks.java | 51 ---- .../model/firmware/FirmwareArtifacts.java | 63 ----- .../firmware/FirmwareAutoAssignRequest.java | 71 ----- .../firmware/FirmwareDistributionSet.java | 153 ---------- .../FirmwareDistributionSetAssignment.java | 103 ------- ...rmwareDistributionSetAssignmentResult.java | 73 ----- .../FirmwareDistributionSetResource.java | 21 +- .../firmware/FirmwareDistributionSetType.java | 122 -------- .../FirmwareDistributionSetTypeResource.java | 32 ++- .../FirmwareDistributionSetTypes.java | 63 ----- .../firmware/FirmwareDistributionSets.java | 63 ----- .../hawkbit/model/firmware/FirmwareLink.java | 51 ---- .../firmware/FirmwareMaintenanceWindow.java | 61 ---- .../model/firmware/FirmwareMetadata.java | 56 ---- .../model/firmware/FirmwareMetadataList.java | 63 ----- .../firmware/FirmwareMetadataUpdate.java | 21 +- .../model/firmware/FirmwarePollStatus.java | 61 ---- .../model/firmware/FirmwareRollout.java | 263 ------------------ .../model/firmware/FirmwareRolloutAction.java | 51 ---- .../firmware/FirmwareRolloutCondition.java | 51 ---- .../model/firmware/FirmwareRolloutGroup.java | 163 ----------- .../model/firmware/FirmwareRolloutGroups.java | 63 ----- .../firmware/FirmwareRolloutRequest.java | 171 ------------ .../firmware/FirmwareRolloutResource.java | 34 +-- .../model/firmware/FirmwareRollouts.java | 63 ----- .../firmware/FirmwareSoftwareModule.java | 141 ---------- .../FirmwareSoftwareModuleResource.java | 24 +- .../firmware/FirmwareSoftwareModuleType.java | 111 -------- .../FirmwareSoftwareModuleTypeAssignment.java | 41 --- .../FirmwareSoftwareModuleTypeResource.java | 16 +- .../firmware/FirmwareSoftwareModuleTypes.java | 63 ----- .../firmware/FirmwareSoftwareModules.java | 63 ----- .../model/firmware/FirmwareTarget.java | 164 +---------- .../firmware/FirmwareTargetAssignment.java | 91 ------ .../firmware/FirmwareTargetFilterQueries.java | 63 ----- .../firmware/FirmwareTargetFilterQuery.java | 101 ------- .../FirmwareTargetFilterQueryRequest.java | 51 ---- .../FirmwareTargetFilterResource.java | 26 +- .../firmware/FirmwareTargetResource.java | 31 ++- .../model/firmware/FirmwareTargets.java | 63 ----- 62 files changed, 540 insertions(+), 3563 deletions(-) create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java rename hawkbit/src/main/java/org/openremote/extension/hawkbit/{model/firmware/FirmwareAssignedAction.java => manager/hawkbit/HawkbitMediaType.java} (60%) delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadata.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataList.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java index b76d42b..a13dd8d 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.manager.firmware; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; @@ -27,15 +28,8 @@ import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetAssignment; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetAssignmentResult; import org.openremote.model.http.RequestParams; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetResource; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSets; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetAssignment; - -import java.util.List; public class FirmwareDistributionSetResourceImpl extends ManagerWebResource implements FirmwareDistributionSetResource { @@ -49,12 +43,10 @@ public FirmwareDistributionSetResourceImpl(TimerService timerService, ManagerIde } @Override - public FirmwareDistributionSet createDistributionSet(RequestParams requestParams, - FirmwareDistributionSet distributionSet) { + public Response createDistributionSet(RequestParams requestParams, + JsonNode distributionSet) { try { - FirmwareDistributionSet[] created = - firmwareService.distributionSetsResource.create(new FirmwareDistributionSet[] { distributionSet }); - return created != null && created.length > 0 ? created[0] : null; + return HawkbitResponse.from(firmwareService.distributionSetsResource.create(distributionSet)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to create firmware distribution set", e, Response.Status.BAD_GATEWAY); @@ -62,29 +54,16 @@ public FirmwareDistributionSet createDistributionSet(RequestParams requestParams } @Override - public FirmwareDistributionSetAssignmentResult assignDistributionSet(RequestParams requestParams, Long id, - FirmwareDistributionSetAssignment assignment) { + public Response assignDistributionSet(RequestParams requestParams, Long id, + Boolean offline, + JsonNode targets) { try { - if (assignment == null || assignment.getTargets() == null || assignment.getTargets().isEmpty()) { + if (targets == null || !targets.isArray() || targets.isEmpty()) { throw new WebApplicationException("Assignment requires at least one target", Response.Status.BAD_REQUEST); } - List targets = assignment.getTargets().stream() - .map(target -> new FirmwareTargetAssignment() - .setId(target.getId()) - .setForcetime(target.getForcetime() != null ? target.getForcetime() : assignment.getForcetime()) - .setWeight(target.getWeight() != null ? target.getWeight() : assignment.getWeight()) - .setConfirmationRequired(target.getConfirmationRequired() != null - ? target.getConfirmationRequired() - : assignment.getConfirmationRequired()) - .setType(target.getType() != null ? target.getType() : assignment.getType()) - .setMaintenanceWindow(target.getMaintenanceWindow() != null - ? target.getMaintenanceWindow() - : assignment.getMaintenanceWindow())) - .toList(); - - return firmwareService.distributionSetsResource.assignTargets(id, assignment.getOffline(), - targets.toArray(FirmwareTargetAssignment[]::new)); + return HawkbitResponse.from(firmwareService.distributionSetsResource.assignTargets(id, offline, targets)) + .asResource(); } catch (WebApplicationException e) { throw e; } catch (Exception e) { @@ -94,9 +73,10 @@ public FirmwareDistributionSetAssignmentResult assignDistributionSet(RequestPara } @Override - public FirmwareDistributionSets getDistributionSets(RequestParams requestParams, Integer offset, Integer limit) { + public Response getDistributionSets(RequestParams requestParams, Integer offset, Integer limit) { try { - return firmwareService.distributionSetsResource.getDistributionSets(offset, limit); + return HawkbitResponse.from(firmwareService.distributionSetsResource.getDistributionSets(offset, limit)) + .asPage(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware distribution sets", e, Response.Status.BAD_GATEWAY); @@ -104,9 +84,9 @@ public FirmwareDistributionSets getDistributionSets(RequestParams requestParams, } @Override - public FirmwareDistributionSet getDistributionSet(RequestParams requestParams, Long id) { + public Response getDistributionSet(RequestParams requestParams, Long id) { try { - return firmwareService.distributionSetsResource.get(id); + return HawkbitResponse.from(firmwareService.distributionSetsResource.get(id)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware distribution set '" + id + "'", e, Response.Status.BAD_GATEWAY); diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java index 00eefc4..1e923bc 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java @@ -19,16 +19,14 @@ */ package org.openremote.extension.hawkbit.manager.firmware; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetType; import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypeResource; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypes; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleType; public class FirmwareDistributionSetTypeResourceImpl extends ManagerWebResource implements FirmwareDistributionSetTypeResource { @@ -43,12 +41,11 @@ public FirmwareDistributionSetTypeResourceImpl(TimerService timerService, } @Override - public FirmwareDistributionSetType createDistributionSetType(RequestParams requestParams, - FirmwareDistributionSetType distributionSetType) { + public Response createDistributionSetType(RequestParams requestParams, + JsonNode distributionSetType) { try { - FirmwareDistributionSetType[] created = firmwareService.distributionSetTypesResource.create( - new FirmwareDistributionSetType[] { distributionSetType }); - return created != null && created.length > 0 ? created[0] : null; + return HawkbitResponse.from(firmwareService.distributionSetTypesResource.create(distributionSetType)) + .asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to create firmware distribution set type", e, Response.Status.BAD_GATEWAY); @@ -56,10 +53,11 @@ public FirmwareDistributionSetType createDistributionSetType(RequestParams reque } @Override - public FirmwareDistributionSetTypes getDistributionSetTypes(RequestParams requestParams, Integer offset, - Integer limit) { + public Response getDistributionSetTypes(RequestParams requestParams, Integer offset, + Integer limit) { try { - return firmwareService.distributionSetTypesResource.getDistributionSetTypes(offset, limit); + return HawkbitResponse.from(firmwareService.distributionSetTypesResource.getDistributionSetTypes(offset, limit)) + .asPage(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware distribution set types", e, Response.Status.BAD_GATEWAY); @@ -67,9 +65,9 @@ public FirmwareDistributionSetTypes getDistributionSetTypes(RequestParams reques } @Override - public FirmwareDistributionSetType getDistributionSetType(RequestParams requestParams, Long id) { + public Response getDistributionSetType(RequestParams requestParams, Long id) { try { - return firmwareService.distributionSetTypesResource.get(id); + return HawkbitResponse.from(firmwareService.distributionSetTypesResource.get(id)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware distribution set type '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -77,10 +75,11 @@ public FirmwareDistributionSetType getDistributionSetType(RequestParams requestP } @Override - public FirmwareSoftwareModuleType[] getMandatoryModuleTypes(RequestParams requestParams, Long id, Integer offset, - Integer limit) { + public Response getMandatoryModuleTypes(RequestParams requestParams, Long id, Integer offset, + Integer limit) { try { - return firmwareService.distributionSetTypesResource.getMandatoryModuleTypes(id, offset, limit); + return HawkbitResponse.from(firmwareService.distributionSetTypesResource.getMandatoryModuleTypes(id, offset, limit)) + .asPage(); } catch (Exception e) { throw new WebApplicationException( "Failed to retrieve mandatory module types for firmware distribution set type '" + id + "'", @@ -89,10 +88,11 @@ public FirmwareSoftwareModuleType[] getMandatoryModuleTypes(RequestParams reques } @Override - public FirmwareSoftwareModuleType[] getOptionalModuleTypes(RequestParams requestParams, Long id, Integer offset, - Integer limit) { + public Response getOptionalModuleTypes(RequestParams requestParams, Long id, Integer offset, + Integer limit) { try { - return firmwareService.distributionSetTypesResource.getOptionalModuleTypes(id, offset, limit); + return HawkbitResponse.from(firmwareService.distributionSetTypesResource.getOptionalModuleTypes(id, offset, limit)) + .asPage(); } catch (Exception e) { throw new WebApplicationException( "Failed to retrieve optional module types for firmware distribution set type '" + id + "'", diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java index c437a47..644e15c 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java @@ -19,17 +19,13 @@ */ package org.openremote.extension.hawkbit.manager.firmware; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRollout; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutGroup; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutGroups; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutRequest; import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutResource; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRollouts; import org.openremote.model.http.RequestParams; public class FirmwareRolloutResourceImpl extends ManagerWebResource @@ -44,10 +40,10 @@ public FirmwareRolloutResourceImpl(TimerService timerService, ManagerIdentitySer } @Override - public FirmwareRollouts getRollouts(RequestParams requestParams, Integer offset, Integer limit) { + public Response getRollouts(RequestParams requestParams, Integer offset, Integer limit) { try { // Request full representation so totalTargetsPerStatus and totalGroups are populated; hawkBit defaults to compact. - return firmwareService.rolloutsResource.getRollouts(offset, limit, "full"); + return HawkbitResponse.from(firmwareService.rolloutsResource.getRollouts(offset, limit, "full")).asPage(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware rollouts", e, Response.Status.BAD_GATEWAY); @@ -55,9 +51,9 @@ public FirmwareRollouts getRollouts(RequestParams requestParams, Integer offset, } @Override - public FirmwareRollout getRollout(RequestParams requestParams, Long id) { + public Response getRollout(RequestParams requestParams, Long id) { try { - return firmwareService.rolloutsResource.get(id); + return HawkbitResponse.from(firmwareService.rolloutsResource.get(id)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware rollout '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -65,9 +61,9 @@ public FirmwareRollout getRollout(RequestParams requestParams, Long id) { } @Override - public FirmwareRollout createRollout(RequestParams requestParams, FirmwareRolloutRequest rollout) { + public Response createRollout(RequestParams requestParams, JsonNode rollout) { try { - return firmwareService.rolloutsResource.create(rollout); + return HawkbitResponse.from(firmwareService.rolloutsResource.create(rollout)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to create firmware rollout", e, Response.Status.BAD_GATEWAY); @@ -85,9 +81,9 @@ public void deleteRollout(RequestParams requestParams, Long id) { } @Override - public FirmwareRollout startRollout(RequestParams requestParams, Long id) { + public Response startRollout(RequestParams requestParams, Long id) { try { - return firmwareService.rolloutsResource.start(id); + return HawkbitResponse.from(firmwareService.rolloutsResource.start(id)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to start firmware rollout '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -105,10 +101,11 @@ public void pauseRollout(RequestParams requestParams, Long id) { } @Override - public FirmwareRolloutGroups getRolloutGroups(RequestParams requestParams, Long id, - Integer offset, Integer limit) { + public Response getRolloutGroups(RequestParams requestParams, Long id, + Integer offset, Integer limit) { try { - return firmwareService.rolloutsResource.getRolloutGroups(id, offset, limit, "full"); + return HawkbitResponse.from(firmwareService.rolloutsResource.getRolloutGroups(id, offset, limit, "full")) + .asPage(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve groups for rollout '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -116,9 +113,9 @@ public FirmwareRolloutGroups getRolloutGroups(RequestParams requestParams, Long } @Override - public FirmwareRolloutGroup getRolloutGroup(RequestParams requestParams, Long id, Long groupId) { + public Response getRolloutGroup(RequestParams requestParams, Long id, Long groupId) { try { - return firmwareService.rolloutsResource.getRolloutGroup(id, groupId); + return HawkbitResponse.from(firmwareService.rolloutsResource.getRolloutGroup(id, groupId)).asResource(); } catch (Exception e) { throw new WebApplicationException( "Failed to retrieve group '" + groupId + "' for rollout '" + id + "'", e, diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java index 3830a31..e015fd1 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java @@ -35,8 +35,10 @@ import java.util.logging.Logger; import jakarta.ws.rs.NotFoundException; +import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.client.ClientRequestFilter; import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; @@ -65,7 +67,6 @@ import org.openremote.model.attribute.Attribute; import org.openremote.model.attribute.AttributeEvent; import org.openremote.model.attribute.MetaMap; -import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifact; import org.openremote.extension.hawkbit.model.firmware.FirmwareMetaItemType; import org.openremote.extension.hawkbit.model.firmware.FirmwareMetadataUpdate; import org.openremote.extension.hawkbit.model.firmware.FirmwareTarget; @@ -211,11 +212,11 @@ public void stop(Container container) throws Exception { } - public FirmwareArtifact uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream inputStream, + public Response uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream inputStream, String originalFilename, String filename) throws IOException, InterruptedException { - return artifactUploadClient.uploadSoftwareModuleArtifact(softwareModuleId, inputStream, - originalFilename, filename); + return HawkbitResponse.from(artifactUploadClient.uploadSoftwareModuleArtifact(softwareModuleId, inputStream, + originalFilename, filename)).asResource(); } private void onAssetChange(AssetEvent assetEvent) { @@ -276,7 +277,7 @@ private void handleAssetChange(AssetEvent assetEvent) { case UPDATE: LOG.info("Checking hawkbit target for update asset id=" + asset.getId()); try { - FirmwareTarget existingTarget = targetsResource.get(controllerId); + FirmwareTarget existingTarget = getFirmwareTarget(controllerId); if (existingTarget != null) { LOG.info("hawkbit target already exists so nothing to do id=" + controllerId); shouldUpdateFirmwareTargetInfo = true; @@ -420,12 +421,16 @@ private FirmwareTarget buildFirmwareTarget(Asset asset) { } private boolean createFirmwareTarget(FirmwareTarget target) { - LOG.info("Creating hawkbit target id=" + target.getControllerId()); - try { - targetsResource.create(new FirmwareTarget[] { target }); - return true; + LOG.info("Creating hawkbit target id=" + target.controllerId()); + try (Response response = targetsResource.create(new FirmwareTarget[] { target })) { + boolean created = response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL; + if (!created) { + LOG.warning("Failed to create hawkbit target id=" + target.controllerId() + + ", status=" + response.getStatus()); + } + return created; } catch (Exception e) { - LOG.log(Level.WARNING, "Failed to create hawkbit target id=" + target.getControllerId(), e); + LOG.log(Level.WARNING, "Failed to create hawkbit target id=" + target.controllerId(), e); return false; } } @@ -453,10 +458,13 @@ private void updateFirmwareTargetInfo(AssetEvent assetEvent) { case CREATE: case UPDATE: try { - FirmwareTarget firmwareTarget = targetsResource.get(controllerId); + FirmwareTarget firmwareTarget = getFirmwareTarget(controllerId); + if (firmwareTarget == null) { + return; + } Map firmwareTargetInfo = new LinkedHashMap<>(); - firmwareTargetInfo.put("controllerId", firmwareTarget.getControllerId()); - firmwareTargetInfo.put("securityToken", firmwareTarget.getSecurityToken()); + firmwareTargetInfo.put("controllerId", firmwareTarget.controllerId()); + firmwareTargetInfo.put("securityToken", firmwareTarget.securityToken()); assetProcessingService.sendAttributeEvent( new AttributeEvent( asset.getId(), @@ -464,7 +472,7 @@ private void updateFirmwareTargetInfo(AssetEvent assetEvent) { ValueUtil.asJSON(firmwareTargetInfo).orElse(null)), getClass().getSimpleName()); LOG.info("Updated firmware target info attribute for asset id=" + asset.getId() - + ", controllerId=" + firmwareTarget.getControllerId()); + + ", controllerId=" + firmwareTarget.controllerId()); } catch (Exception e) { LOG.log(Level.WARNING, "Failed to update firmware target info for asset id=" + asset.getId(), e); } @@ -474,4 +482,17 @@ private void updateFirmwareTargetInfo(AssetEvent assetEvent) { } } + private FirmwareTarget getFirmwareTarget(String controllerId) { + try (Response response = targetsResource.get(controllerId)) { + if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { + return null; + } + if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { + throw new WebApplicationException("hawkBit target request failed with status " + response.getStatus(), + response.getStatus()); + } + return response.readEntity(FirmwareTarget.class); + } + } + } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java index ff554dd..b00f97e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.manager.firmware; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.POST; @@ -34,11 +35,7 @@ import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifact; -import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifacts; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModule; import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleResource; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModules; import java.io.InputStream; import java.util.List; @@ -55,12 +52,10 @@ public FirmwareSoftwareModuleResourceImpl(TimerService timerService, ManagerIden } @Override - public FirmwareSoftwareModule createSoftwareModule(RequestParams requestParams, - FirmwareSoftwareModule softwareModule) { + public Response createSoftwareModule(RequestParams requestParams, + JsonNode softwareModule) { try { - FirmwareSoftwareModule[] created = - firmwareService.softwareModulesResource.create(new FirmwareSoftwareModule[] { softwareModule }); - return created != null && created.length > 0 ? created[0] : null; + return HawkbitResponse.from(firmwareService.softwareModulesResource.create(softwareModule)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to create firmware software module", e, Response.Status.BAD_GATEWAY); @@ -68,9 +63,9 @@ public FirmwareSoftwareModule createSoftwareModule(RequestParams requestParams, } @Override - public FirmwareSoftwareModules getSoftwareModules(RequestParams requestParams, Integer offset, Integer limit) { + public Response getSoftwareModules(RequestParams requestParams, Integer offset, Integer limit) { try { - return firmwareService.softwareModulesResource.getSoftwareModules(offset, limit); + return HawkbitResponse.from(firmwareService.softwareModulesResource.getSoftwareModules(offset, limit)).asPage(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware software modules", e, Response.Status.BAD_GATEWAY); @@ -78,9 +73,9 @@ public FirmwareSoftwareModules getSoftwareModules(RequestParams requestParams, I } @Override - public FirmwareSoftwareModule getSoftwareModule(RequestParams requestParams, Long id) { + public Response getSoftwareModule(RequestParams requestParams, Long id) { try { - return firmwareService.softwareModulesResource.get(id); + return HawkbitResponse.from(firmwareService.softwareModulesResource.get(id)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware software module '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -88,9 +83,9 @@ public FirmwareSoftwareModule getSoftwareModule(RequestParams requestParams, Lon } @Override - public FirmwareArtifacts getSoftwareModuleArtifacts(RequestParams requestParams, Long id) { + public Response getSoftwareModuleArtifacts(RequestParams requestParams, Long id) { try { - return firmwareService.softwareModulesResource.getArtifacts(id); + return HawkbitResponse.from(firmwareService.softwareModulesResource.getArtifacts(id)).asPage(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve artifacts for firmware software module '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -101,10 +96,10 @@ public FirmwareArtifacts getSoftwareModuleArtifacts(RequestParams requestParams, @Path("{id}/artifacts") @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) - public FirmwareArtifact uploadSoftwareModuleArtifact(RequestParams requestParams, - @PathParam("id") Long id, - @QueryParam("filename") String filename, - List parts) { + public Response uploadSoftwareModuleArtifact(RequestParams requestParams, + @PathParam("id") Long id, + @QueryParam("filename") String filename, + List parts) { try { EntityPart filePart = parts == null ? null : parts.stream() .filter(part -> "file".equals(part.getName())) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java index cb329f9..61171a5 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java @@ -19,15 +19,14 @@ */ package org.openremote.extension.hawkbit.manager.firmware; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleType; import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypeResource; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypes; public class FirmwareSoftwareModuleTypeResourceImpl extends ManagerWebResource implements FirmwareSoftwareModuleTypeResource { @@ -41,12 +40,11 @@ public FirmwareSoftwareModuleTypeResourceImpl(TimerService timerService, Manager } @Override - public FirmwareSoftwareModuleType createSoftwareModuleType(RequestParams requestParams, - FirmwareSoftwareModuleType softwareModuleType) { + public Response createSoftwareModuleType(RequestParams requestParams, + JsonNode softwareModuleType) { try { - FirmwareSoftwareModuleType[] created = firmwareService.softwareModuleTypesResource.create( - new FirmwareSoftwareModuleType[] { softwareModuleType }); - return created != null && created.length > 0 ? created[0] : null; + return HawkbitResponse.from(firmwareService.softwareModuleTypesResource.create(softwareModuleType)) + .asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to create firmware software module type", e, Response.Status.BAD_GATEWAY); @@ -54,10 +52,11 @@ public FirmwareSoftwareModuleType createSoftwareModuleType(RequestParams request } @Override - public FirmwareSoftwareModuleTypes getSoftwareModuleTypes(RequestParams requestParams, Integer offset, - Integer limit) { + public Response getSoftwareModuleTypes(RequestParams requestParams, Integer offset, + Integer limit) { try { - return firmwareService.softwareModuleTypesResource.getSoftwareModuleTypes(offset, limit); + return HawkbitResponse.from(firmwareService.softwareModuleTypesResource.getSoftwareModuleTypes(offset, limit)) + .asPage(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware software module types", e, Response.Status.BAD_GATEWAY); @@ -65,9 +64,9 @@ public FirmwareSoftwareModuleTypes getSoftwareModuleTypes(RequestParams requestP } @Override - public FirmwareSoftwareModuleType getSoftwareModuleType(RequestParams requestParams, Long id) { + public Response getSoftwareModuleType(RequestParams requestParams, Long id) { try { - return firmwareService.softwareModuleTypesResource.get(id); + return HawkbitResponse.from(firmwareService.softwareModuleTypesResource.get(id)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware software module type '" + id + "'", e, Response.Status.BAD_GATEWAY); diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java index c779cef..0d0122c 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java @@ -19,16 +19,12 @@ */ package org.openremote.extension.hawkbit.manager.firmware; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; -import org.openremote.extension.hawkbit.model.firmware.FirmwareAutoAssignRequest; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQueries; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQuery; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQueryRequest; import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterResource; import org.openremote.model.http.RequestParams; @@ -44,9 +40,9 @@ public FirmwareTargetFilterResourceImpl(TimerService timerService, ManagerIdenti } @Override - public FirmwareTargetFilterQueries getTargetFilters(RequestParams requestParams, Integer offset, Integer limit) { + public Response getTargetFilters(RequestParams requestParams, Integer offset, Integer limit) { try { - return firmwareService.targetFiltersResource.getTargetFilters(offset, limit); + return HawkbitResponse.from(firmwareService.targetFiltersResource.getTargetFilters(offset, limit)).asPage(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware target filters", e, Response.Status.BAD_GATEWAY); @@ -54,9 +50,9 @@ public FirmwareTargetFilterQueries getTargetFilters(RequestParams requestParams, } @Override - public FirmwareTargetFilterQuery getTargetFilter(RequestParams requestParams, Long id) { + public Response getTargetFilter(RequestParams requestParams, Long id) { try { - return firmwareService.targetFiltersResource.get(id); + return HawkbitResponse.from(firmwareService.targetFiltersResource.get(id)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware target filter '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -64,10 +60,10 @@ public FirmwareTargetFilterQuery getTargetFilter(RequestParams requestParams, Lo } @Override - public FirmwareTargetFilterQuery createTargetFilter(RequestParams requestParams, - FirmwareTargetFilterQueryRequest filter) { + public Response createTargetFilter(RequestParams requestParams, + JsonNode filter) { try { - return firmwareService.targetFiltersResource.create(filter); + return HawkbitResponse.from(firmwareService.targetFiltersResource.create(filter)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to create firmware target filter", e, Response.Status.BAD_GATEWAY); @@ -85,9 +81,9 @@ public void deleteTargetFilter(RequestParams requestParams, Long id) { } @Override - public FirmwareDistributionSet getAutoAssignDS(RequestParams requestParams, Long id) { + public Response getAutoAssignDS(RequestParams requestParams, Long id) { try { - return firmwareService.targetFiltersResource.getAutoAssignDS(id); + return HawkbitResponse.from(firmwareService.targetFiltersResource.getAutoAssignDS(id)).asResource(); } catch (Exception e) { throw new WebApplicationException( "Failed to retrieve auto assign distribution set for filter '" + id + "'", e, @@ -96,10 +92,10 @@ public FirmwareDistributionSet getAutoAssignDS(RequestParams requestParams, Long } @Override - public FirmwareTargetFilterQuery setAutoAssignDS(RequestParams requestParams, Long id, - FirmwareAutoAssignRequest request) { + public Response setAutoAssignDS(RequestParams requestParams, Long id, + JsonNode request) { try { - return firmwareService.targetFiltersResource.setAutoAssignDS(id, request); + return HawkbitResponse.from(firmwareService.targetFiltersResource.setAutoAssignDS(id, request)).asResource(); } catch (Exception e) { throw new WebApplicationException( "Failed to set auto assign distribution set for filter '" + id + "'", e, diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java index 13518a8..fe92a92 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java @@ -25,13 +25,7 @@ import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -import org.openremote.extension.hawkbit.model.firmware.FirmwareAction; -import org.openremote.extension.hawkbit.model.firmware.FirmwareActions; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; -import org.openremote.extension.hawkbit.model.firmware.FirmwareMetadataList; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTarget; import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetResource; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargets; public class FirmwareTargetResourceImpl extends ManagerWebResource implements FirmwareTargetResource { @@ -44,18 +38,18 @@ public FirmwareTargetResourceImpl(TimerService timerService, ManagerIdentityServ } @Override - public FirmwareTargets getTargets(RequestParams requestParams, String query, Integer offset, Integer limit) { + public Response getTargets(RequestParams requestParams, String query, Integer offset, Integer limit) { try { - return firmwareService.targetsResource.getTargets(query, offset, limit); + return HawkbitResponse.from(firmwareService.targetsResource.getTargets(query, offset, limit)).asPage(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware targets", e, Response.Status.BAD_GATEWAY); } } @Override - public FirmwareTarget getTarget(RequestParams requestParams, String id) { + public Response getTarget(RequestParams requestParams, String id) { try { - return firmwareService.targetsResource.get(id); + return HawkbitResponse.from(firmwareService.targetsResource.get(id)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve firmware target '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -63,9 +57,9 @@ public FirmwareTarget getTarget(RequestParams requestParams, String id) { } @Override - public FirmwareMetadataList getMetadata(RequestParams requestParams, String id) { + public Response getMetadata(RequestParams requestParams, String id) { try { - return firmwareService.targetsResource.getMetadata(id); + return HawkbitResponse.from(firmwareService.targetsResource.getMetadata(id)).asPage(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve metadata for firmware target '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -73,9 +67,9 @@ public FirmwareMetadataList getMetadata(RequestParams requestParams, String id) } @Override - public FirmwareDistributionSet getAssignedDs(RequestParams requestParams, String id) { + public Response getAssignedDs(RequestParams requestParams, String id) { try { - return firmwareService.targetsResource.getAssignedDs(id); + return HawkbitResponse.from(firmwareService.targetsResource.getAssignedDs(id)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve assigned DS for firmware target '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -83,9 +77,9 @@ public FirmwareDistributionSet getAssignedDs(RequestParams requestParams, String } @Override - public FirmwareDistributionSet getInstalledDs(RequestParams requestParams, String id) { + public Response getInstalledDs(RequestParams requestParams, String id) { try { - return firmwareService.targetsResource.getInstalledDs(id); + return HawkbitResponse.from(firmwareService.targetsResource.getInstalledDs(id)).asResource(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve installed DS for firmware target '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -93,9 +87,9 @@ public FirmwareDistributionSet getInstalledDs(RequestParams requestParams, Strin } @Override - public FirmwareActions getActions(RequestParams requestParams, String id, Integer offset, Integer limit) { + public Response getActions(RequestParams requestParams, String id, Integer offset, Integer limit) { try { - return firmwareService.targetsResource.getActions(id, offset, limit); + return HawkbitResponse.from(firmwareService.targetsResource.getActions(id, offset, limit)).asPage(); } catch (Exception e) { throw new WebApplicationException("Failed to retrieve actions for firmware target '" + id + "'", e, Response.Status.BAD_GATEWAY); @@ -103,9 +97,9 @@ public FirmwareActions getActions(RequestParams requestParams, String id, Intege } @Override - public FirmwareAction getAction(RequestParams requestParams, String id, Long actionId) { + public Response getAction(RequestParams requestParams, String id, Long actionId) { try { - return firmwareService.targetsResource.getAction(id, actionId); + return HawkbitResponse.from(firmwareService.targetsResource.getAction(id, actionId)).asResource(); } catch (Exception e) { throw new WebApplicationException( "Failed to retrieve action '" + actionId + "' for firmware target '" + id + "'", e, diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java new file mode 100644 index 0000000..255a2c2 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java @@ -0,0 +1,196 @@ +/* + * Copyright 2026, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.manager.firmware; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.openremote.model.util.ValueUtil; + +import java.util.LinkedHashMap; +import java.util.Map; + +class HawkbitResponse { + + private static final Map DEFAULT_LINK_ID_FIELDS = Map.of( + "distributionset", "distributionSetId"); + + private final Response response; + private final Map linkIdFields = new LinkedHashMap<>(DEFAULT_LINK_ID_FIELDS); + + private HawkbitResponse(Response response) { + this.response = response; + } + + static HawkbitResponse from(Response response) { + return new HawkbitResponse(response); + } + + HawkbitResponse withLinkId(String rel, String fieldName) { + linkIdFields.put(rel, fieldName); + return this; + } + + Response asResource() { + return formatResponse(Mode.HAL); + } + + Response asPage() { + return formatResponse(Mode.PAGED); + } + + Response raw() { + return response; + } + + private Response formatResponse(Mode mode) { + try (response) { + Response.ResponseBuilder builder = Response.status(response.getStatus()); + if (!response.hasEntity()) { + return builder.build(); + } + + String body = response.readEntity(String.class); + if (body == null || body.isBlank()) { + return builder.build(); + } + + try { + JsonNode formatted = switch (mode) { + case HAL -> stripHal(ValueUtil.JSON.readTree(body)); + case PAGED -> toPagedResponse(ValueUtil.JSON.readTree(body)); + }; + return builder + .type(MediaType.APPLICATION_JSON_TYPE) + .entity(ValueUtil.JSON.writeValueAsString(formatted)) + .build(); + } catch (Exception ignored) { + MediaType mediaType = response.getMediaType() == null + ? MediaType.TEXT_PLAIN_TYPE + : response.getMediaType(); + return builder.type(mediaType).entity(body).build(); + } + } catch (Exception e) { + throw new WebApplicationException("Failed to format hawkBit response", e, + Response.Status.BAD_GATEWAY); + } + } + + private ObjectNode toPagedResponse(JsonNode root) { + ArrayNode content = JsonNodeFactory.instance.arrayNode(); + if (root.isArray()) { + root.forEach(item -> content.add(stripHal(item))); + } else if (root.isObject() && root.has("_embedded")) { + embeddedContent(root.get("_embedded")).forEach(item -> content.add(stripHal(item))); + } else if (root.isObject() && root.path("content").isArray()) { + root.get("content").forEach(item -> content.add(stripHal(item))); + } else if (!root.isMissingNode() && !root.isNull()) { + content.add(stripHal(root)); + } + + ObjectNode formatted = JsonNodeFactory.instance.objectNode(); + formatted.set("content", content); + formatted.put("total", intValue(root, "total", intValue(root.path("page"), "totalElements", content.size()))); + formatted.put("size", intValue(root, "size", intValue(root.path("page"), "size", content.size()))); + return formatted; + } + + private JsonNode stripHal(JsonNode node) { + if (node.isArray()) { + ArrayNode formatted = JsonNodeFactory.instance.arrayNode(); + node.forEach(item -> formatted.add(stripHal(item))); + return formatted; + } + + if (!node.isObject()) { + return node; + } + + ObjectNode formatted = JsonNodeFactory.instance.objectNode(); + for (Map.Entry field : node.properties()) { + if ("_links".equals(field.getKey()) || "_embedded".equals(field.getKey())) { + continue; + } + formatted.set(field.getKey(), stripHal(field.getValue())); + } + addMappedLinkIds(node.path("_links"), formatted); + return formatted; + } + + private void addMappedLinkIds(JsonNode links, ObjectNode target) { + if (!links.isObject()) { + return; + } + + linkIdFields.forEach((rel, fieldName) -> { + Long id = idFromHref(links.path(rel).path("href")); + if (id != null && !target.has(fieldName)) { + target.put(fieldName, id); + } + }); + } + + private static Long idFromHref(JsonNode hrefNode) { + if (!hrefNode.isTextual()) { + return null; + } + + String href = hrefNode.textValue(); + int end = href.endsWith("/") ? href.length() - 1 : href.length(); + int start = href.lastIndexOf('/', end - 1) + 1; + if (start < 0 || start >= end) { + return null; + } + try { + return Long.parseLong(href.substring(start, end)); + } catch (NumberFormatException ignored) { + return null; + } + } + + private static ArrayNode embeddedContent(JsonNode embedded) { + ArrayNode content = JsonNodeFactory.instance.arrayNode(); + if (!embedded.isObject()) { + return content; + } + + for (JsonNode value : embedded) { + if (value.isArray()) { + value.forEach(content::add); + return content; + } + } + return content; + } + + private static int intValue(JsonNode node, String field, int defaultValue) { + JsonNode value = node.path(field); + return value.isNumber() ? value.intValue() : defaultValue; + } + + private enum Mode { + HAL, + PAGED + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java index cfc9bf4..3806dd7 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java @@ -19,9 +19,8 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifact; +import jakarta.ws.rs.core.Response; import org.openremote.model.util.TextUtil; -import org.openremote.model.util.ValueUtil; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -34,6 +33,8 @@ import java.nio.charset.StandardCharsets; import java.util.UUID; +import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; + public class HawkbitArtifactUploadClient { protected final URI hawkbitManagementUri; @@ -46,8 +47,8 @@ public HawkbitArtifactUploadClient(URI hawkbitManagementUri, String hawkbitUsern this.hawkbitPassword = hawkbitPassword; } - public FirmwareArtifact uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream inputStream, - String originalFilename, String filename) + public Response uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream inputStream, + String originalFilename, String filename) throws IOException, InterruptedException { String effectiveFilename = TextUtil.isNullOrEmpty(filename) ? originalFilename : filename; String boundary = "----OpenRemoteBoundary" + UUID.randomUUID(); @@ -56,7 +57,7 @@ public FirmwareArtifact uploadSoftwareModuleArtifact(Long softwareModuleId, Inpu HttpRequest request = HttpRequest.newBuilder( buildArtifactUploadUri(softwareModuleId, effectiveFilename)) .header("Authorization", HawkbitBasicAuth.buildAuthorizationHeader(hawkbitUsername, hawkbitPassword)) - .header("Accept", "application/hal+json") + .header("Accept", APPLICATION_HAL_JSON) .header("Content-Type", "multipart/form-data; boundary=" + boundary) .POST(HttpRequest.BodyPublishers.ofByteArray(payload)) .build(); @@ -64,11 +65,10 @@ public FirmwareArtifact uploadSoftwareModuleArtifact(Long softwareModuleId, Inpu HttpResponse response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); - if (response.statusCode() < 200 || response.statusCode() >= 300) { - throw new IOException("Artifact upload failed with status " + response.statusCode() + ": " + response.body()); - } - - return ValueUtil.JSON.readValue(response.body(), FirmwareArtifact.class); + return Response.status(response.statusCode()) + .type(response.headers().firstValue("content-type").orElse(APPLICATION_HAL_JSON)) + .entity(response.body()) + .build(); } protected URI buildArtifactUploadUri(Long softwareModuleId, String filename) { diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java index 95b841e..92f663d 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -27,45 +28,42 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetType; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypes; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleType; +import jakarta.ws.rs.core.Response; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("distributionsettypes") public interface HawkbitDistributionSetTypesResource { - String APPLICATION_HAL_JSON = "application/hal+json"; - @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - FirmwareDistributionSetType[] create(FirmwareDistributionSetType[] distributionSetTypes); + Response create(JsonNode distributionSetTypes); @GET @Produces(APPLICATION_JSON) - FirmwareDistributionSetTypes getDistributionSetTypes(@QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getDistributionSetTypes(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @Produces(APPLICATION_JSON) - FirmwareDistributionSetType get(@PathParam("id") Long id); + Response get(@PathParam("id") Long id); @GET @Path("{id}/mandatorymoduletypes") @Produces(APPLICATION_JSON) - FirmwareSoftwareModuleType[] getMandatoryModuleTypes(@PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getMandatoryModuleTypes(@PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}/optionalmoduletypes") @Produces(APPLICATION_JSON) - FirmwareSoftwareModuleType[] getOptionalModuleTypes(@PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getOptionalModuleTypes(@PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java index 6b9963c..834cba8 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; import jakarta.ws.rs.Consumes; @@ -27,40 +28,36 @@ import jakarta.ws.rs.POST; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetAssignmentResult; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetAssignment; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSets; +import jakarta.ws.rs.core.Response; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("distributionsets") public interface HawkbitDistributionSetsResource { - String APPLICATION_HAL_JSON = "application/hal+json"; - @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - FirmwareDistributionSet[] create(FirmwareDistributionSet[] distributionSets); + Response create(JsonNode distributionSets); @POST @Path("{id}/assignedTargets") @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - FirmwareDistributionSetAssignmentResult assignTargets(@PathParam("id") Long id, - @QueryParam("offline") Boolean offline, - FirmwareTargetAssignment[] targets); + Response assignTargets(@PathParam("id") Long id, + @QueryParam("offline") Boolean offline, + JsonNode targets); @GET @Produces(APPLICATION_JSON) - FirmwareDistributionSets getDistributionSets(@QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getDistributionSets(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @Produces(APPLICATION_JSON) - FirmwareDistributionSet get(@PathParam("id") Long id); + Response get(@PathParam("id") Long id); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAssignedAction.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitMediaType.java similarity index 60% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAssignedAction.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitMediaType.java index 739a12a..64b5236 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAssignedAction.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitMediaType.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, OpenRemote Inc. + * Copyright 2026, OpenRemote Inc. * * See the CONTRIBUTORS.txt file in the distribution for a * full listing of individual contributors. @@ -17,25 +17,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.manager.hawkbit; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +public final class HawkbitMediaType { -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareAssignedAction { - protected Long id; + public static final String APPLICATION_HAL_JSON = "application/hal+json"; - @JsonCreator - protected FirmwareAssignedAction() { - } - - public Long getId() { - return id; - } - - public FirmwareAssignedAction setId(Long id) { - this.id = id; - return this; + private HawkbitMediaType() { } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java index c499ca0..906b6dd 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -27,34 +28,29 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRollout; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutGroup; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutGroups; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutRequest; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRollouts; +import jakarta.ws.rs.core.Response; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("rollouts") public interface HawkbitRolloutsResource { - String APPLICATION_HAL_JSON = "application/hal+json"; - @GET @Produces(APPLICATION_JSON) - FirmwareRollouts getRollouts(@QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit, - @QueryParam("representation") String representation); + Response getRollouts(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit, + @QueryParam("representation") String representation); @GET @Path("{id}") @Produces(APPLICATION_JSON) - FirmwareRollout get(@PathParam("id") Long id); + Response get(@PathParam("id") Long id); @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - FirmwareRollout create(FirmwareRolloutRequest rollout); + Response create(JsonNode rollout); @DELETE @Path("{id}") @@ -63,7 +59,7 @@ FirmwareRollouts getRollouts(@QueryParam("offset") Integer offset, @POST @Path("{id}/start") @Produces(APPLICATION_HAL_JSON) - FirmwareRollout start(@PathParam("id") Long id); + Response start(@PathParam("id") Long id); @POST @Path("{id}/pause") @@ -72,14 +68,14 @@ FirmwareRollouts getRollouts(@QueryParam("offset") Integer offset, @GET @Path("{id}/deploygroups") @Produces(APPLICATION_JSON) - FirmwareRolloutGroups getRolloutGroups(@PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit, - @QueryParam("representation") String representation); + Response getRolloutGroups(@PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit, + @QueryParam("representation") String representation); @GET @Path("{id}/deploygroups/{groupId}") @Produces(APPLICATION_JSON) - FirmwareRolloutGroup getRolloutGroup(@PathParam("id") Long id, - @PathParam("groupId") Long groupId); + Response getRolloutGroup(@PathParam("id") Long id, + @PathParam("groupId") Long groupId); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java index a901f7f..6b0fab7 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -27,30 +28,28 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleType; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypes; +import jakarta.ws.rs.core.Response; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("softwaremoduletypes") public interface HawkbitSoftwareModuleTypesResource { - String APPLICATION_HAL_JSON = "application/hal+json"; - @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - FirmwareSoftwareModuleType[] create(FirmwareSoftwareModuleType[] softwareModuleTypes); + Response create(JsonNode softwareModuleTypes); @GET @Produces(APPLICATION_JSON) - FirmwareSoftwareModuleTypes getSoftwareModuleTypes(@QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getSoftwareModuleTypes(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @Produces(APPLICATION_JSON) - FirmwareSoftwareModuleType get(@PathParam("id") Long id); + Response get(@PathParam("id") Long id); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java index 179e4aa..afb9142 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; import jakarta.ws.rs.Consumes; @@ -27,36 +28,33 @@ import jakarta.ws.rs.POST; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; -import org.openremote.extension.hawkbit.model.firmware.FirmwareArtifacts; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModule; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModules; +import jakarta.ws.rs.core.Response; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("softwaremodules") public interface HawkbitSoftwareModulesResource { - String APPLICATION_HAL_JSON = "application/hal+json"; - @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - FirmwareSoftwareModule[] create(FirmwareSoftwareModule[] softwareModules); + Response create(JsonNode softwareModules); @GET @Produces(APPLICATION_JSON) - FirmwareSoftwareModules getSoftwareModules(@QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getSoftwareModules(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @Produces(APPLICATION_JSON) - FirmwareSoftwareModule get(@PathParam("id") Long id); + Response get(@PathParam("id") Long id); @GET @Path("{id}/artifacts") @Produces(APPLICATION_JSON) - FirmwareArtifacts getArtifacts(@PathParam("id") Long id); + Response getArtifacts(@PathParam("id") Long id); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java index 3dfb7c6..3c5c252 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -27,33 +28,28 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; -import org.openremote.extension.hawkbit.model.firmware.FirmwareAutoAssignRequest; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQueries; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQuery; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterQueryRequest; +import jakarta.ws.rs.core.Response; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("targetfilters") public interface HawkbitTargetFiltersResource { - String APPLICATION_HAL_JSON = "application/hal+json"; - @GET @Produces(APPLICATION_JSON) - FirmwareTargetFilterQueries getTargetFilters(@QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getTargetFilters(@QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{filterId}") @Produces(APPLICATION_JSON) - FirmwareTargetFilterQuery get(@PathParam("filterId") Long filterId); + Response get(@PathParam("filterId") Long filterId); @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - FirmwareTargetFilterQuery create(FirmwareTargetFilterQueryRequest filter); + Response create(JsonNode filter); @DELETE @Path("{filterId}") @@ -62,14 +58,14 @@ FirmwareTargetFilterQueries getTargetFilters(@QueryParam("offset") Integer offse @GET @Path("{filterId}/autoAssignDS") @Produces(APPLICATION_JSON) - FirmwareDistributionSet getAutoAssignDS(@PathParam("filterId") Long filterId); + Response getAutoAssignDS(@PathParam("filterId") Long filterId); @POST @Path("{filterId}/autoAssignDS") @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - FirmwareTargetFilterQuery setAutoAssignDS(@PathParam("filterId") Long filterId, - FirmwareAutoAssignRequest request); + Response setAutoAssignDS(@PathParam("filterId") Long filterId, + JsonNode request); @DELETE @Path("{filterId}/autoAssignDS") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java index d820aa2..f93aa49 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java @@ -20,39 +20,36 @@ package org.openremote.extension.hawkbit.manager.hawkbit; import jakarta.ws.rs.*; -import org.openremote.extension.hawkbit.model.firmware.FirmwareAction; -import org.openremote.extension.hawkbit.model.firmware.FirmwareActions; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSet; -import org.openremote.extension.hawkbit.model.firmware.FirmwareMetadataList; +import jakarta.ws.rs.core.Response; import org.openremote.extension.hawkbit.model.firmware.FirmwareMetadataUpdate; import org.openremote.extension.hawkbit.model.firmware.FirmwareTarget; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargets; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("targets") public interface HawkbitTargetsResource { @GET @Produces(APPLICATION_JSON) - FirmwareTargets getTargets(@QueryParam("q") String query, @QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit); + Response getTargets(@QueryParam("q") String query, @QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit); @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) - FirmwareTarget[] create(FirmwareTarget[] targets); + Response create(FirmwareTarget[] targets); @GET @Path("{id}") @Produces(APPLICATION_JSON) - FirmwareTarget get(@PathParam("id") String id); + Response get(@PathParam("id") String id); @PUT @Path("{id}") @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) - FirmwareTarget update(@PathParam("id") String id, FirmwareTarget target); + Response update(@PathParam("id") String id, FirmwareTarget target); @DELETE @Path("{id}") @@ -61,7 +58,7 @@ public interface HawkbitTargetsResource { @GET @Path("{id}/metadata") @Produces(APPLICATION_JSON) - FirmwareMetadataList getMetadata(@PathParam("id") String id); + Response getMetadata(@PathParam("id") String id); @PUT @Path("{id}/metadata/{key}") @@ -77,24 +74,24 @@ void updateMetadata(@PathParam("id") String id, @GET @Path("{id}/assignedDS") @Produces(APPLICATION_JSON) - FirmwareDistributionSet getAssignedDs(@PathParam("id") String id); + Response getAssignedDs(@PathParam("id") String id); @GET @Path("{id}/installedDS") @Produces(APPLICATION_JSON) - FirmwareDistributionSet getInstalledDs(@PathParam("id") String id); + Response getInstalledDs(@PathParam("id") String id); @GET @Path("{id}/actions") - @Produces("application/hal+json") - FirmwareActions getActions(@PathParam("id") String id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @Produces(APPLICATION_HAL_JSON) + Response getActions(@PathParam("id") String id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}/actions/{actionId}") - @Produces("application/hal+json") - FirmwareAction getAction(@PathParam("id") String id, @PathParam("actionId") Long actionId); + @Produces(APPLICATION_HAL_JSON) + Response getAction(@PathParam("id") String id, @PathParam("actionId") Long actionId); @DELETE @Path("{id}/actions/{actionId}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java deleted file mode 100644 index 4200daf..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAction.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareAction { - protected Long id; - protected String status; - protected String type; - protected String forceType; - protected Long forceTime; - protected Integer weight; - protected Boolean active; - protected Long createdAt; - protected Long lastModifiedAt; - protected Integer lastStatusCode; - protected FirmwareDistributionSet distributionSet; - protected FirmwareMaintenanceWindow maintenanceWindow; - @JsonProperty("_links") - protected FirmwareActionLinks links; - - @JsonCreator - protected FirmwareAction() { - } - - public Long getId() { - return id; - } - - public FirmwareAction setId(Long id) { - this.id = id; - return this; - } - - public String getStatus() { - return status; - } - - public FirmwareAction setStatus(String status) { - this.status = status; - return this; - } - - public String getType() { - return type; - } - - public FirmwareAction setType(String type) { - this.type = type; - return this; - } - - public String getForceType() { - return forceType; - } - - public FirmwareAction setForceType(String forceType) { - this.forceType = forceType; - return this; - } - - public Long getForceTime() { - return forceTime; - } - - public FirmwareAction setForceTime(Long forceTime) { - this.forceTime = forceTime; - return this; - } - - public Integer getWeight() { - return weight; - } - - public FirmwareAction setWeight(Integer weight) { - this.weight = weight; - return this; - } - - public Boolean getActive() { - return active; - } - - public FirmwareAction setActive(Boolean active) { - this.active = active; - return this; - } - - public Long getCreatedAt() { - return createdAt; - } - - public FirmwareAction setCreatedAt(Long createdAt) { - this.createdAt = createdAt; - return this; - } - - public Long getLastModifiedAt() { - return lastModifiedAt; - } - - public FirmwareAction setLastModifiedAt(Long lastModifiedAt) { - this.lastModifiedAt = lastModifiedAt; - return this; - } - - public Integer getLastStatusCode() { - return lastStatusCode; - } - - public FirmwareAction setLastStatusCode(Integer lastStatusCode) { - this.lastStatusCode = lastStatusCode; - return this; - } - - public FirmwareDistributionSet getDistributionSet() { - return distributionSet; - } - - public FirmwareAction setDistributionSet(FirmwareDistributionSet distributionSet) { - this.distributionSet = distributionSet; - return this; - } - - public FirmwareMaintenanceWindow getMaintenanceWindow() { - return maintenanceWindow; - } - - public FirmwareAction setMaintenanceWindow(FirmwareMaintenanceWindow maintenanceWindow) { - this.maintenanceWindow = maintenanceWindow; - return this; - } - - public FirmwareActionLinks getLinks() { - return links; - } - - public FirmwareAction setLinks(FirmwareActionLinks links) { - this.links = links; - return this; - } - - public Long getDistributionSetId() { - if (links == null || links.getDistributionset() == null || links.getDistributionset().getHref() == null) { - return null; - } - String href = links.getDistributionset().getHref(); - String[] parts = href.split("/"); - try { - return Long.parseLong(parts[parts.length - 1]); - } catch (NumberFormatException e) { - return null; - } - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java deleted file mode 100644 index 71d0ba1..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActionLinks.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareActionLinks { - protected FirmwareLink distributionset; - - @JsonCreator - protected FirmwareActionLinks() { - } - - public FirmwareLink getDistributionset() { - return distributionset; - } - - public FirmwareActionLinks setDistributionset(FirmwareLink distributionset) { - this.distributionset = distributionset; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java deleted file mode 100644 index 0689df1..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareActions.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareActions { - protected List content; - protected int total; - protected int size; - - @JsonCreator - protected FirmwareActions() { - } - - public List getContent() { - return content; - } - - public FirmwareActions setContent(List content) { - this.content = content; - return this; - } - - public int getTotal() { - return total; - } - - public FirmwareActions setTotal(int total) { - this.total = total; - return this; - } - - public int getSize() { - return size; - } - - public FirmwareActions setSize(int size) { - this.size = size; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java deleted file mode 100644 index a0a511e..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifact.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.Map; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareArtifact { - protected Long id; - protected String providedFilename; - protected Long size; - protected Map hashes; - protected FirmwareArtifactLinks _links; - - @JsonCreator - protected FirmwareArtifact() { - } - - public Long getId() { - return id; - } - - public FirmwareArtifact setId(Long id) { - this.id = id; - return this; - } - - public String getProvidedFilename() { - return providedFilename; - } - - public FirmwareArtifact setProvidedFilename(String providedFilename) { - this.providedFilename = providedFilename; - return this; - } - - public Long getSize() { - return size; - } - - public FirmwareArtifact setSize(Long size) { - this.size = size; - return this; - } - - public Map getHashes() { - return hashes; - } - - public FirmwareArtifact setHashes(Map hashes) { - this.hashes = hashes; - return this; - } - - public FirmwareArtifactLinks get_links() { - return _links; - } - - public FirmwareArtifact set_links(FirmwareArtifactLinks links) { - this._links = links; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java deleted file mode 100644 index 3e737f1..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifactLinks.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareArtifactLinks { - protected FirmwareLink self; - protected FirmwareLink download; - - @JsonCreator - protected FirmwareArtifactLinks() { - } - - public FirmwareLink getSelf() { - return self; - } - - public FirmwareArtifactLinks setSelf(FirmwareLink self) { - this.self = self; - return this; - } - - public FirmwareLink getDownload() { - return download; - } - - public FirmwareArtifactLinks setDownload(FirmwareLink download) { - this.download = download; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java deleted file mode 100644 index 7c28791..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareArtifacts.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareArtifacts { - protected List content; - - protected FirmwareArtifacts() { - } - - @JsonCreator(mode = JsonCreator.Mode.DELEGATING) - public FirmwareArtifacts(List content) { - this.content = content; - } - - public List getContent() { - return content; - } - - public FirmwareArtifacts setContent(List content) { - this.content = content; - return this; - } - - public int getTotal() { - return content == null ? 0 : content.size(); - } - - public FirmwareArtifacts setTotal(int total) { - return this; - } - - public int getSize() { - return content == null ? 0 : content.size(); - } - - public FirmwareArtifacts setSize(int size) { - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java deleted file mode 100644 index 5f450fc..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignRequest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareAutoAssignRequest { - protected Long id; - protected String type; - protected Integer weight; - protected Boolean confirmationRequired; - - @JsonCreator - public FirmwareAutoAssignRequest() { - } - - public Long getId() { - return id; - } - - public FirmwareAutoAssignRequest setId(Long id) { - this.id = id; - return this; - } - - public String getType() { - return type; - } - - public FirmwareAutoAssignRequest setType(String type) { - this.type = type; - return this; - } - - public Integer getWeight() { - return weight; - } - - public FirmwareAutoAssignRequest setWeight(Integer weight) { - this.weight = weight; - return this; - } - - public Boolean getConfirmationRequired() { - return confirmationRequired; - } - - public FirmwareAutoAssignRequest setConfirmationRequired(Boolean confirmationRequired) { - this.confirmationRequired = confirmationRequired; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java deleted file mode 100644 index 17dc5e5..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSet.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonCreator; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareDistributionSet { - protected Long id; - protected String name; - protected String description; - protected String version; - protected String type; - protected String typeName; - protected Boolean locked; - protected Boolean deleted; - protected Boolean valid; - protected Boolean complete; - protected Boolean requiredMigrationStep; - protected List modules; - - @JsonCreator - protected FirmwareDistributionSet() { - } - - public Long getId() { - return id; - } - - public FirmwareDistributionSet setId(Long id) { - this.id = id; - return this; - } - - public String getName() { - return name; - } - - public FirmwareDistributionSet setName(String name) { - this.name = name; - return this; - } - - public String getDescription() { - return description; - } - - public FirmwareDistributionSet setDescription(String description) { - this.description = description; - return this; - } - - public String getVersion() { - return version; - } - - public FirmwareDistributionSet setVersion(String version) { - this.version = version; - return this; - } - - public String getType() { - return type; - } - - public FirmwareDistributionSet setType(String type) { - this.type = type; - return this; - } - - public String getTypeName() { - return typeName; - } - - public FirmwareDistributionSet setTypeName(String typeName) { - this.typeName = typeName; - return this; - } - - public Boolean getLocked() { - return locked; - } - - public FirmwareDistributionSet setLocked(Boolean locked) { - this.locked = locked; - return this; - } - - public Boolean getDeleted() { - return deleted; - } - - public FirmwareDistributionSet setDeleted(Boolean deleted) { - this.deleted = deleted; - return this; - } - - public Boolean getValid() { - return valid; - } - - public FirmwareDistributionSet setValid(Boolean valid) { - this.valid = valid; - return this; - } - - public Boolean getComplete() { - return complete; - } - - public FirmwareDistributionSet setComplete(Boolean complete) { - this.complete = complete; - return this; - } - - public Boolean getRequiredMigrationStep() { - return requiredMigrationStep; - } - - public FirmwareDistributionSet setRequiredMigrationStep(Boolean requiredMigrationStep) { - this.requiredMigrationStep = requiredMigrationStep; - return this; - } - - public List getModules() { - return modules; - } - - public FirmwareDistributionSet setModules(List modules) { - this.modules = modules; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java deleted file mode 100644 index b9efbac..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareDistributionSetAssignment { - protected List targets; - protected Boolean offline; - protected Long forcetime; - protected Integer weight; - protected Boolean confirmationRequired; - protected String type; - protected FirmwareMaintenanceWindow maintenanceWindow; - - @JsonCreator - protected FirmwareDistributionSetAssignment() { - } - - public List getTargets() { - return targets; - } - - public FirmwareDistributionSetAssignment setTargets(List targets) { - this.targets = targets; - return this; - } - - public Boolean getOffline() { - return offline; - } - - public FirmwareDistributionSetAssignment setOffline(Boolean offline) { - this.offline = offline; - return this; - } - - public Long getForcetime() { - return forcetime; - } - - public FirmwareDistributionSetAssignment setForcetime(Long forcetime) { - this.forcetime = forcetime; - return this; - } - - public Integer getWeight() { - return weight; - } - - public FirmwareDistributionSetAssignment setWeight(Integer weight) { - this.weight = weight; - return this; - } - - public Boolean getConfirmationRequired() { - return confirmationRequired; - } - - public FirmwareDistributionSetAssignment setConfirmationRequired(Boolean confirmationRequired) { - this.confirmationRequired = confirmationRequired; - return this; - } - - public String getType() { - return type; - } - - public FirmwareDistributionSetAssignment setType(String type) { - this.type = type; - return this; - } - - public FirmwareMaintenanceWindow getMaintenanceWindow() { - return maintenanceWindow; - } - - public FirmwareDistributionSetAssignment setMaintenanceWindow(FirmwareMaintenanceWindow maintenanceWindow) { - this.maintenanceWindow = maintenanceWindow; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java deleted file mode 100644 index 898042e..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignmentResult.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareDistributionSetAssignmentResult { - protected Integer alreadyAssigned; - protected Integer assigned; - protected Integer total; - protected List assignedActions; - - @JsonCreator - protected FirmwareDistributionSetAssignmentResult() { - } - - public Integer getAlreadyAssigned() { - return alreadyAssigned; - } - - public FirmwareDistributionSetAssignmentResult setAlreadyAssigned(Integer alreadyAssigned) { - this.alreadyAssigned = alreadyAssigned; - return this; - } - - public Integer getAssigned() { - return assigned; - } - - public FirmwareDistributionSetAssignmentResult setAssigned(Integer assigned) { - this.assigned = assigned; - return this; - } - - public Integer getTotal() { - return total; - } - - public FirmwareDistributionSetAssignmentResult setTotal(Integer total) { - this.total = total; - return this; - } - - public List getAssignedActions() { - return assignedActions; - } - - public FirmwareDistributionSetAssignmentResult setAssignedActions(List assignedActions) { - this.assignedActions = assignedActions; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java index 7c0a1e9..7ffbd7f 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.model.firmware; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -30,6 +31,7 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -44,30 +46,31 @@ public interface FirmwareDistributionSetResource { @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - FirmwareDistributionSet createDistributionSet(@BeanParam RequestParams requestParams, - FirmwareDistributionSet distributionSet); + Response createDistributionSet(@BeanParam RequestParams requestParams, + JsonNode distributionSet); @POST @Path("{id}/assign") @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - FirmwareDistributionSetAssignmentResult assignDistributionSet(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - FirmwareDistributionSetAssignment assignment); + Response assignDistributionSet(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + @QueryParam("offline") Boolean offline, + JsonNode targets); @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareDistributionSets getDistributionSets(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getDistributionSets(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareDistributionSet getDistributionSet(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + Response getDistributionSet(@BeanParam RequestParams requestParams, @PathParam("id") Long id); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java deleted file mode 100644 index 21e9cc7..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetType.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareDistributionSetType { - protected Long id; - protected String name; - protected String description; - protected String key; - protected String colour; - protected Boolean deleted; - @JsonProperty("mandatorymodules") - protected List mandatoryModules; - @JsonProperty("optionalmodules") - protected List optionalModules; - - @JsonCreator - protected FirmwareDistributionSetType() { - } - - public Long getId() { - return id; - } - - public FirmwareDistributionSetType setId(Long id) { - this.id = id; - return this; - } - - public String getName() { - return name; - } - - public FirmwareDistributionSetType setName(String name) { - this.name = name; - return this; - } - - public String getDescription() { - return description; - } - - public FirmwareDistributionSetType setDescription(String description) { - this.description = description; - return this; - } - - public String getKey() { - return key; - } - - public FirmwareDistributionSetType setKey(String key) { - this.key = key; - return this; - } - - public String getColour() { - return colour; - } - - public FirmwareDistributionSetType setColour(String colour) { - this.colour = colour; - return this; - } - - public Boolean getDeleted() { - return deleted; - } - - public FirmwareDistributionSetType setDeleted(Boolean deleted) { - this.deleted = deleted; - return this; - } - - @JsonProperty("mandatorymodules") - public List getMandatoryModules() { - return mandatoryModules; - } - - @JsonProperty("mandatorymodules") - public FirmwareDistributionSetType setMandatoryModules( - List mandatoryModules) { - this.mandatoryModules = mandatoryModules; - return this; - } - - @JsonProperty("optionalmodules") - public List getOptionalModules() { - return optionalModules; - } - - @JsonProperty("optionalmodules") - public FirmwareDistributionSetType setOptionalModules( - List optionalModules) { - this.optionalModules = optionalModules; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java index 6c1b2c6..f3c375a 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.model.firmware; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -30,6 +31,7 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -44,40 +46,40 @@ public interface FirmwareDistributionSetTypeResource { @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - FirmwareDistributionSetType createDistributionSetType(@BeanParam RequestParams requestParams, - FirmwareDistributionSetType distributionSetType); + Response createDistributionSetType(@BeanParam RequestParams requestParams, + JsonNode distributionSetType); @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareDistributionSetTypes getDistributionSetTypes(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getDistributionSetTypes(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareDistributionSetType getDistributionSetType(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + Response getDistributionSetType(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); @GET @Path("{id}/mandatorymoduletypes") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareSoftwareModuleType[] getMandatoryModuleTypes(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getMandatoryModuleTypes(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}/optionalmoduletypes") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareSoftwareModuleType[] getOptionalModuleTypes(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getOptionalModuleTypes(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java deleted file mode 100644 index 58fa4ef..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypes.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareDistributionSetTypes { - protected List content; - protected int total; - protected int size; - - @JsonCreator - protected FirmwareDistributionSetTypes() { - } - - public List getContent() { - return content; - } - - public FirmwareDistributionSetTypes setContent(List content) { - this.content = content; - return this; - } - - public int getTotal() { - return total; - } - - public FirmwareDistributionSetTypes setTotal(int total) { - this.total = total; - return this; - } - - public int getSize() { - return size; - } - - public FirmwareDistributionSetTypes setSize(int size) { - this.size = size; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java deleted file mode 100644 index 491fa18..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSets.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareDistributionSets { - protected List content; - protected int total; - protected int size; - - @JsonCreator - protected FirmwareDistributionSets() { - } - - public List getContent() { - return content; - } - - public FirmwareDistributionSets setContent(List content) { - this.content = content; - return this; - } - - public int getTotal() { - return total; - } - - public FirmwareDistributionSets setTotal(int total) { - this.total = total; - return this; - } - - public int getSize() { - return size; - } - - public FirmwareDistributionSets setSize(int size) { - this.size = size; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java deleted file mode 100644 index 4166398..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareLink.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareLink { - protected String href; - protected String name; - - @JsonCreator - protected FirmwareLink() { - } - - public String getHref() { - return href; - } - - public FirmwareLink setHref(String href) { - this.href = href; - return this; - } - - public String getName() { - return name; - } - - public FirmwareLink setName(String name) { - this.name = name; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java deleted file mode 100644 index f890ac4..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMaintenanceWindow.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareMaintenanceWindow { - protected String schedule; - protected String duration; - protected String timezone; - - @JsonCreator - protected FirmwareMaintenanceWindow() { - } - - public String getSchedule() { - return schedule; - } - - public FirmwareMaintenanceWindow setSchedule(String schedule) { - this.schedule = schedule; - return this; - } - - public String getDuration() { - return duration; - } - - public FirmwareMaintenanceWindow setDuration(String duration) { - this.duration = duration; - return this; - } - - public String getTimezone() { - return timezone; - } - - public FirmwareMaintenanceWindow setTimezone(String timezone) { - this.timezone = timezone; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadata.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadata.java deleted file mode 100644 index 5ecce68..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadata.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareMetadata { - protected String key; - protected String value; - - @JsonCreator - protected FirmwareMetadata() { - } - - public FirmwareMetadata(String key, String value) { - this.key = key; - this.value = value; - } - - public String getKey() { - return key; - } - - public FirmwareMetadata setKey(String key) { - this.key = key; - return this; - } - - public String getValue() { - return value; - } - - public FirmwareMetadata setValue(String value) { - this.value = value; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataList.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataList.java deleted file mode 100644 index 5e6914f..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataList.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareMetadataList { - protected List content; - protected int total; - protected int size; - - @JsonCreator - protected FirmwareMetadataList() { - } - - public List getContent() { - return content; - } - - public FirmwareMetadataList setContent(List content) { - this.content = content; - return this; - } - - public int getTotal() { - return total; - } - - public FirmwareMetadataList setTotal(int total) { - this.total = total; - return this; - } - - public int getSize() { - return size; - } - - public FirmwareMetadataList setSize(int size) { - this.size = size; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataUpdate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataUpdate.java index 87ed414..7a1da9a 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataUpdate.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataUpdate.java @@ -19,27 +19,8 @@ */ package org.openremote.extension.hawkbit.model.firmware; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareMetadataUpdate { - protected String value; - - @JsonCreator - protected FirmwareMetadataUpdate() { - } - - public FirmwareMetadataUpdate(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - public FirmwareMetadataUpdate setValue(String value) { - this.value = value; - return this; - } +public record FirmwareMetadataUpdate(String value) { } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java deleted file mode 100644 index 1d16e62..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwarePollStatus.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwarePollStatus { - protected Long lastRequestAt; - protected Long nextExpectedRequestAt; - protected Boolean overdue; - - @JsonCreator - protected FirmwarePollStatus() { - } - - public Long getLastRequestAt() { - return lastRequestAt; - } - - public FirmwarePollStatus setLastRequestAt(Long lastRequestAt) { - this.lastRequestAt = lastRequestAt; - return this; - } - - public Long getNextExpectedRequestAt() { - return nextExpectedRequestAt; - } - - public FirmwarePollStatus setNextExpectedRequestAt(Long nextExpectedRequestAt) { - this.nextExpectedRequestAt = nextExpectedRequestAt; - return this; - } - - public Boolean getOverdue() { - return overdue; - } - - public FirmwarePollStatus setOverdue(Boolean overdue) { - this.overdue = overdue; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java deleted file mode 100644 index 03c773b..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollout.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.Map; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareRollout { - protected Long id; - protected String name; - protected String description; - protected String targetFilterQuery; - protected Long distributionSetId; - protected String status; - protected Long totalTargets; - protected Map totalTargetsPerStatus; - protected Integer totalGroups; - protected Long startAt; - protected Long forcetime; - protected Boolean deleted; - protected String type; - protected String createdBy; - protected Long createdAt; - protected String lastModifiedBy; - protected Long lastModifiedAt; - protected Integer weight; - protected Boolean confirmationRequired; - protected FirmwareRolloutCondition successCondition; - protected FirmwareRolloutAction successAction; - protected FirmwareRolloutCondition errorCondition; - protected FirmwareRolloutAction errorAction; - - @JsonCreator - protected FirmwareRollout() { - } - - public Long getId() { - return id; - } - - public FirmwareRollout setId(Long id) { - this.id = id; - return this; - } - - public String getName() { - return name; - } - - public FirmwareRollout setName(String name) { - this.name = name; - return this; - } - - public String getDescription() { - return description; - } - - public FirmwareRollout setDescription(String description) { - this.description = description; - return this; - } - - public String getTargetFilterQuery() { - return targetFilterQuery; - } - - public FirmwareRollout setTargetFilterQuery(String targetFilterQuery) { - this.targetFilterQuery = targetFilterQuery; - return this; - } - - public Long getDistributionSetId() { - return distributionSetId; - } - - public FirmwareRollout setDistributionSetId(Long distributionSetId) { - this.distributionSetId = distributionSetId; - return this; - } - - public String getStatus() { - return status; - } - - public FirmwareRollout setStatus(String status) { - this.status = status; - return this; - } - - public Long getTotalTargets() { - return totalTargets; - } - - public FirmwareRollout setTotalTargets(Long totalTargets) { - this.totalTargets = totalTargets; - return this; - } - - public Map getTotalTargetsPerStatus() { - return totalTargetsPerStatus; - } - - public FirmwareRollout setTotalTargetsPerStatus(Map totalTargetsPerStatus) { - this.totalTargetsPerStatus = totalTargetsPerStatus; - return this; - } - - public Integer getTotalGroups() { - return totalGroups; - } - - public FirmwareRollout setTotalGroups(Integer totalGroups) { - this.totalGroups = totalGroups; - return this; - } - - public Long getStartAt() { - return startAt; - } - - public FirmwareRollout setStartAt(Long startAt) { - this.startAt = startAt; - return this; - } - - public Long getForcetime() { - return forcetime; - } - - public FirmwareRollout setForcetime(Long forcetime) { - this.forcetime = forcetime; - return this; - } - - public Boolean getDeleted() { - return deleted; - } - - public FirmwareRollout setDeleted(Boolean deleted) { - this.deleted = deleted; - return this; - } - - public String getType() { - return type; - } - - public FirmwareRollout setType(String type) { - this.type = type; - return this; - } - - public String getCreatedBy() { - return createdBy; - } - - public FirmwareRollout setCreatedBy(String createdBy) { - this.createdBy = createdBy; - return this; - } - - public Long getCreatedAt() { - return createdAt; - } - - public FirmwareRollout setCreatedAt(Long createdAt) { - this.createdAt = createdAt; - return this; - } - - public String getLastModifiedBy() { - return lastModifiedBy; - } - - public FirmwareRollout setLastModifiedBy(String lastModifiedBy) { - this.lastModifiedBy = lastModifiedBy; - return this; - } - - public Long getLastModifiedAt() { - return lastModifiedAt; - } - - public FirmwareRollout setLastModifiedAt(Long lastModifiedAt) { - this.lastModifiedAt = lastModifiedAt; - return this; - } - - public Integer getWeight() { - return weight; - } - - public FirmwareRollout setWeight(Integer weight) { - this.weight = weight; - return this; - } - - public Boolean getConfirmationRequired() { - return confirmationRequired; - } - - public FirmwareRollout setConfirmationRequired(Boolean confirmationRequired) { - this.confirmationRequired = confirmationRequired; - return this; - } - - public FirmwareRolloutCondition getSuccessCondition() { - return successCondition; - } - - public FirmwareRollout setSuccessCondition(FirmwareRolloutCondition successCondition) { - this.successCondition = successCondition; - return this; - } - - public FirmwareRolloutAction getSuccessAction() { - return successAction; - } - - public FirmwareRollout setSuccessAction(FirmwareRolloutAction successAction) { - this.successAction = successAction; - return this; - } - - public FirmwareRolloutCondition getErrorCondition() { - return errorCondition; - } - - public FirmwareRollout setErrorCondition(FirmwareRolloutCondition errorCondition) { - this.errorCondition = errorCondition; - return this; - } - - public FirmwareRolloutAction getErrorAction() { - return errorAction; - } - - public FirmwareRollout setErrorAction(FirmwareRolloutAction errorAction) { - this.errorAction = errorAction; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java deleted file mode 100644 index b6257b5..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareRolloutAction { - protected String action; - protected String expression; - - @JsonCreator - protected FirmwareRolloutAction() { - } - - public String getAction() { - return action; - } - - public FirmwareRolloutAction setAction(String action) { - this.action = action; - return this; - } - - public String getExpression() { - return expression; - } - - public FirmwareRolloutAction setExpression(String expression) { - this.expression = expression; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java deleted file mode 100644 index 1eb8323..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareRolloutCondition { - protected String condition; - protected String expression; - - @JsonCreator - protected FirmwareRolloutCondition() { - } - - public String getCondition() { - return condition; - } - - public FirmwareRolloutCondition setCondition(String condition) { - this.condition = condition; - return this; - } - - public String getExpression() { - return expression; - } - - public FirmwareRolloutCondition setExpression(String expression) { - this.expression = expression; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java deleted file mode 100644 index 24f310d..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroup.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.Map; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareRolloutGroup { - protected Long id; - protected String name; - protected String description; - protected FirmwareRolloutCondition successCondition; - protected FirmwareRolloutAction successAction; - protected FirmwareRolloutCondition errorCondition; - protected FirmwareRolloutAction errorAction; - protected String targetFilterQuery; - protected Integer targetPercentage; - protected Boolean confirmationRequired; - protected String status; - protected Long totalTargets; - protected Map totalTargetsPerStatus; - - @JsonCreator - protected FirmwareRolloutGroup() { - } - - public Long getId() { - return id; - } - - public FirmwareRolloutGroup setId(Long id) { - this.id = id; - return this; - } - - public String getName() { - return name; - } - - public FirmwareRolloutGroup setName(String name) { - this.name = name; - return this; - } - - public String getDescription() { - return description; - } - - public FirmwareRolloutGroup setDescription(String description) { - this.description = description; - return this; - } - - public FirmwareRolloutCondition getSuccessCondition() { - return successCondition; - } - - public FirmwareRolloutGroup setSuccessCondition(FirmwareRolloutCondition successCondition) { - this.successCondition = successCondition; - return this; - } - - public FirmwareRolloutAction getSuccessAction() { - return successAction; - } - - public FirmwareRolloutGroup setSuccessAction(FirmwareRolloutAction successAction) { - this.successAction = successAction; - return this; - } - - public FirmwareRolloutCondition getErrorCondition() { - return errorCondition; - } - - public FirmwareRolloutGroup setErrorCondition(FirmwareRolloutCondition errorCondition) { - this.errorCondition = errorCondition; - return this; - } - - public FirmwareRolloutAction getErrorAction() { - return errorAction; - } - - public FirmwareRolloutGroup setErrorAction(FirmwareRolloutAction errorAction) { - this.errorAction = errorAction; - return this; - } - - public String getTargetFilterQuery() { - return targetFilterQuery; - } - - public FirmwareRolloutGroup setTargetFilterQuery(String targetFilterQuery) { - this.targetFilterQuery = targetFilterQuery; - return this; - } - - public Integer getTargetPercentage() { - return targetPercentage; - } - - public FirmwareRolloutGroup setTargetPercentage(Integer targetPercentage) { - this.targetPercentage = targetPercentage; - return this; - } - - public Boolean getConfirmationRequired() { - return confirmationRequired; - } - - public FirmwareRolloutGroup setConfirmationRequired(Boolean confirmationRequired) { - this.confirmationRequired = confirmationRequired; - return this; - } - - public String getStatus() { - return status; - } - - public FirmwareRolloutGroup setStatus(String status) { - this.status = status; - return this; - } - - public Long getTotalTargets() { - return totalTargets; - } - - public FirmwareRolloutGroup setTotalTargets(Long totalTargets) { - this.totalTargets = totalTargets; - return this; - } - - public Map getTotalTargetsPerStatus() { - return totalTargetsPerStatus; - } - - public FirmwareRolloutGroup setTotalTargetsPerStatus(Map totalTargetsPerStatus) { - this.totalTargetsPerStatus = totalTargetsPerStatus; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java deleted file mode 100644 index ebf6700..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutGroups.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareRolloutGroups { - protected List content; - protected int total; - protected int size; - - @JsonCreator - protected FirmwareRolloutGroups() { - } - - public List getContent() { - return content; - } - - public FirmwareRolloutGroups setContent(List content) { - this.content = content; - return this; - } - - public int getTotal() { - return total; - } - - public FirmwareRolloutGroups setTotal(int total) { - this.total = total; - return this; - } - - public int getSize() { - return size; - } - - public FirmwareRolloutGroups setSize(int size) { - this.size = size; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java deleted file mode 100644 index a9370d8..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutRequest.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareRolloutRequest { - protected String name; - protected String description; - protected String targetFilterQuery; - protected Long distributionSetId; - protected Integer amountGroups; - protected Long forcetime; - protected Long startAt; - protected Integer weight; - protected String type; - protected FirmwareRolloutCondition successCondition; - protected FirmwareRolloutAction successAction; - protected FirmwareRolloutCondition errorCondition; - protected FirmwareRolloutAction errorAction; - protected Boolean confirmationRequired; - - @JsonCreator - public FirmwareRolloutRequest() { - } - - public String getName() { - return name; - } - - public FirmwareRolloutRequest setName(String name) { - this.name = name; - return this; - } - - public String getDescription() { - return description; - } - - public FirmwareRolloutRequest setDescription(String description) { - this.description = description; - return this; - } - - public String getTargetFilterQuery() { - return targetFilterQuery; - } - - public FirmwareRolloutRequest setTargetFilterQuery(String targetFilterQuery) { - this.targetFilterQuery = targetFilterQuery; - return this; - } - - public Long getDistributionSetId() { - return distributionSetId; - } - - public FirmwareRolloutRequest setDistributionSetId(Long distributionSetId) { - this.distributionSetId = distributionSetId; - return this; - } - - public Integer getAmountGroups() { - return amountGroups; - } - - public FirmwareRolloutRequest setAmountGroups(Integer amountGroups) { - this.amountGroups = amountGroups; - return this; - } - - public Long getForcetime() { - return forcetime; - } - - public FirmwareRolloutRequest setForcetime(Long forcetime) { - this.forcetime = forcetime; - return this; - } - - public Long getStartAt() { - return startAt; - } - - public FirmwareRolloutRequest setStartAt(Long startAt) { - this.startAt = startAt; - return this; - } - - public Integer getWeight() { - return weight; - } - - public FirmwareRolloutRequest setWeight(Integer weight) { - this.weight = weight; - return this; - } - - public String getType() { - return type; - } - - public FirmwareRolloutRequest setType(String type) { - this.type = type; - return this; - } - - public FirmwareRolloutCondition getSuccessCondition() { - return successCondition; - } - - public FirmwareRolloutRequest setSuccessCondition(FirmwareRolloutCondition successCondition) { - this.successCondition = successCondition; - return this; - } - - public FirmwareRolloutAction getSuccessAction() { - return successAction; - } - - public FirmwareRolloutRequest setSuccessAction(FirmwareRolloutAction successAction) { - this.successAction = successAction; - return this; - } - - public FirmwareRolloutCondition getErrorCondition() { - return errorCondition; - } - - public FirmwareRolloutRequest setErrorCondition(FirmwareRolloutCondition errorCondition) { - this.errorCondition = errorCondition; - return this; - } - - public FirmwareRolloutAction getErrorAction() { - return errorAction; - } - - public FirmwareRolloutRequest setErrorAction(FirmwareRolloutAction errorAction) { - this.errorAction = errorAction; - return this; - } - - public Boolean getConfirmationRequired() { - return confirmationRequired; - } - - public FirmwareRolloutRequest setConfirmationRequired(Boolean confirmationRequired) { - this.confirmationRequired = confirmationRequired; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java index 4d9709c..d6d3ced 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.model.firmware; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -30,6 +31,7 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -43,23 +45,23 @@ public interface FirmwareRolloutResource { @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareRollouts getRollouts(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getRollouts(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareRollout getRollout(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + Response getRollout(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - FirmwareRollout createRollout(@BeanParam RequestParams requestParams, - FirmwareRolloutRequest rollout); + Response createRollout(@BeanParam RequestParams requestParams, + JsonNode rollout); @DELETE @Path("{id}") @@ -72,8 +74,8 @@ void deleteRollout(@BeanParam RequestParams requestParams, @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - FirmwareRollout startRollout(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + Response startRollout(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); @POST @Path("{id}/pause") @@ -85,16 +87,16 @@ void pauseRollout(@BeanParam RequestParams requestParams, @Path("{id}/deploygroups") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareRolloutGroups getRolloutGroups(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getRolloutGroups(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}/deploygroups/{groupId}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareRolloutGroup getRolloutGroup(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - @PathParam("groupId") Long groupId); + Response getRolloutGroup(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + @PathParam("groupId") Long groupId); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java deleted file mode 100644 index b2a2c3f..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRollouts.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareRollouts { - protected List content; - protected int total; - protected int size; - - @JsonCreator - protected FirmwareRollouts() { - } - - public List getContent() { - return content; - } - - public FirmwareRollouts setContent(List content) { - this.content = content; - return this; - } - - public int getTotal() { - return total; - } - - public FirmwareRollouts setTotal(int total) { - this.total = total; - return this; - } - - public int getSize() { - return size; - } - - public FirmwareRollouts setSize(int size) { - this.size = size; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java deleted file mode 100644 index 85cdedf..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModule.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareSoftwareModule { - protected Long id; - protected String name; - protected String description; - protected String version; - protected String type; - protected String typeName; - protected String vendor; - protected Boolean encrypted; - protected Boolean locked; - protected Boolean deleted; - protected Boolean complete; - - @JsonCreator - protected FirmwareSoftwareModule() { - } - - public Long getId() { - return id; - } - - public FirmwareSoftwareModule setId(Long id) { - this.id = id; - return this; - } - - public String getName() { - return name; - } - - public FirmwareSoftwareModule setName(String name) { - this.name = name; - return this; - } - - public String getDescription() { - return description; - } - - public FirmwareSoftwareModule setDescription(String description) { - this.description = description; - return this; - } - - public String getVersion() { - return version; - } - - public FirmwareSoftwareModule setVersion(String version) { - this.version = version; - return this; - } - - public String getType() { - return type; - } - - public FirmwareSoftwareModule setType(String type) { - this.type = type; - return this; - } - - public String getTypeName() { - return typeName; - } - - public FirmwareSoftwareModule setTypeName(String typeName) { - this.typeName = typeName; - return this; - } - - public String getVendor() { - return vendor; - } - - public FirmwareSoftwareModule setVendor(String vendor) { - this.vendor = vendor; - return this; - } - - public Boolean getEncrypted() { - return encrypted; - } - - public FirmwareSoftwareModule setEncrypted(Boolean encrypted) { - this.encrypted = encrypted; - return this; - } - - public Boolean getLocked() { - return locked; - } - - public FirmwareSoftwareModule setLocked(Boolean locked) { - this.locked = locked; - return this; - } - - public Boolean getDeleted() { - return deleted; - } - - public FirmwareSoftwareModule setDeleted(Boolean deleted) { - this.deleted = deleted; - return this; - } - - public Boolean getComplete() { - return complete; - } - - public FirmwareSoftwareModule setComplete(Boolean complete) { - this.complete = complete; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java index 3945c62..683500d 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.model.firmware; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -31,6 +32,7 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.Response; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -48,37 +50,37 @@ public interface FirmwareSoftwareModuleResource { @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - FirmwareSoftwareModule createSoftwareModule(@BeanParam RequestParams requestParams, - FirmwareSoftwareModule softwareModule); + Response createSoftwareModule(@BeanParam RequestParams requestParams, + JsonNode softwareModule); @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareSoftwareModules getSoftwareModules(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getSoftwareModules(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareSoftwareModule getSoftwareModule(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + Response getSoftwareModule(@BeanParam RequestParams requestParams, @PathParam("id") Long id); @GET @Path("{id}/artifacts") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareArtifacts getSoftwareModuleArtifacts(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + Response getSoftwareModuleArtifacts(@BeanParam RequestParams requestParams, @PathParam("id") Long id); @POST @Path("{id}/artifacts") @Consumes(MULTIPART_FORM_DATA) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - FirmwareArtifact uploadSoftwareModuleArtifact(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - @QueryParam("filename") String filename, - List parts); + Response uploadSoftwareModuleArtifact(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + @QueryParam("filename") String filename, + List parts); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java deleted file mode 100644 index af8214d..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleType.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareSoftwareModuleType { - protected Long id; - protected String name; - protected String description; - protected String key; - protected Integer minArtifacts; - protected Integer maxAssignments; - protected String colour; - protected Boolean deleted; - - @JsonCreator - protected FirmwareSoftwareModuleType() { - } - - public Long getId() { - return id; - } - - public FirmwareSoftwareModuleType setId(Long id) { - this.id = id; - return this; - } - - public String getName() { - return name; - } - - public FirmwareSoftwareModuleType setName(String name) { - this.name = name; - return this; - } - - public String getDescription() { - return description; - } - - public FirmwareSoftwareModuleType setDescription(String description) { - this.description = description; - return this; - } - - public String getKey() { - return key; - } - - public FirmwareSoftwareModuleType setKey(String key) { - this.key = key; - return this; - } - - public Integer getMinArtifacts() { - return minArtifacts; - } - - public FirmwareSoftwareModuleType setMinArtifacts(Integer minArtifacts) { - this.minArtifacts = minArtifacts; - return this; - } - - public Integer getMaxAssignments() { - return maxAssignments; - } - - public FirmwareSoftwareModuleType setMaxAssignments(Integer maxAssignments) { - this.maxAssignments = maxAssignments; - return this; - } - - public String getColour() { - return colour; - } - - public FirmwareSoftwareModuleType setColour(String colour) { - this.colour = colour; - return this; - } - - public Boolean getDeleted() { - return deleted; - } - - public FirmwareSoftwareModuleType setDeleted(Boolean deleted) { - this.deleted = deleted; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java deleted file mode 100644 index f7a349e..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeAssignment.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareSoftwareModuleTypeAssignment { - protected Long id; - - @JsonCreator - protected FirmwareSoftwareModuleTypeAssignment() { - } - - public Long getId() { - return id; - } - - public FirmwareSoftwareModuleTypeAssignment setId(Long id) { - this.id = id; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java index b46dbce..b69dfc2 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.model.firmware; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -30,6 +31,7 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -44,22 +46,22 @@ public interface FirmwareSoftwareModuleTypeResource { @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - FirmwareSoftwareModuleType createSoftwareModuleType(@BeanParam RequestParams requestParams, - FirmwareSoftwareModuleType softwareModuleType); + Response createSoftwareModuleType(@BeanParam RequestParams requestParams, + JsonNode softwareModuleType); @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareSoftwareModuleTypes getSoftwareModuleTypes(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getSoftwareModuleTypes(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareSoftwareModuleType getSoftwareModuleType(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + Response getSoftwareModuleType(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java deleted file mode 100644 index 50e6f1c..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypes.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareSoftwareModuleTypes { - protected List content; - protected int total; - protected int size; - - @JsonCreator - protected FirmwareSoftwareModuleTypes() { - } - - public List getContent() { - return content; - } - - public FirmwareSoftwareModuleTypes setContent(List content) { - this.content = content; - return this; - } - - public int getTotal() { - return total; - } - - public FirmwareSoftwareModuleTypes setTotal(int total) { - this.total = total; - return this; - } - - public int getSize() { - return size; - } - - public FirmwareSoftwareModuleTypes setSize(int size) { - this.size = size; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java deleted file mode 100644 index fe1dec4..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModules.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareSoftwareModules { - protected List content; - protected int total; - protected int size; - - @JsonCreator - protected FirmwareSoftwareModules() { - } - - public List getContent() { - return content; - } - - public FirmwareSoftwareModules setContent(List content) { - this.content = content; - return this; - } - - public int getTotal() { - return total; - } - - public FirmwareSoftwareModules setTotal(int total) { - this.total = total; - return this; - } - - public int getSize() { - return size; - } - - public FirmwareSoftwareModules setSize(int size) { - this.size = size; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java index b4c9984..a005a8b 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java @@ -19,159 +19,25 @@ */ package org.openremote.extension.hawkbit.model.firmware; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareTarget { - protected String controllerId; - protected String name; - protected String description; - protected String securityToken; - protected String updateStatus; - protected Long lastControllerRequestAt; - protected Long installedAt; - protected String ipAddress; - protected String address; - protected FirmwarePollStatus pollStatus; - protected Boolean requestAttributes; - protected Long targetType; - protected String targetTypeName; - protected Boolean autoConfirmActive; - - @JsonCreator - protected FirmwareTarget() { - } +public record FirmwareTarget( + String controllerId, + String name, + String description, + String securityToken, + String updateStatus, + Long lastControllerRequestAt, + Long installedAt, + String ipAddress, + String address, + Boolean requestAttributes, + Long targetType, + String targetTypeName, + Boolean autoConfirmActive) { public FirmwareTarget(String controllerId, String name, String description) { - this.controllerId = controllerId; - this.name = name; - this.description = description; - } - - public String getControllerId() { - return controllerId; - } - - public FirmwareTarget setControllerId(String controllerId) { - this.controllerId = controllerId; - return this; - } - - public String getName() { - return name; - } - - public FirmwareTarget setName(String name) { - this.name = name; - return this; - } - - public String getDescription() { - return description; - } - - public FirmwareTarget setDescription(String description) { - this.description = description; - return this; - } - - public String getSecurityToken() { - return securityToken; - } - - public FirmwareTarget setSecurityToken(String securityToken) { - this.securityToken = securityToken; - return this; - } - - public String getUpdateStatus() { - return updateStatus; - } - - public FirmwareTarget setUpdateStatus(String updateStatus) { - this.updateStatus = updateStatus; - return this; - } - - public Long getLastControllerRequestAt() { - return lastControllerRequestAt; - } - - public FirmwareTarget setLastControllerRequestAt(Long lastControllerRequestAt) { - this.lastControllerRequestAt = lastControllerRequestAt; - return this; - } - - public Long getInstalledAt() { - return installedAt; - } - - public FirmwareTarget setInstalledAt(Long installedAt) { - this.installedAt = installedAt; - return this; - } - - public String getIpAddress() { - return ipAddress; - } - - public FirmwareTarget setIpAddress(String ipAddress) { - this.ipAddress = ipAddress; - return this; - } - - public String getAddress() { - return address; - } - - public FirmwareTarget setAddress(String address) { - this.address = address; - return this; - } - - public FirmwarePollStatus getPollStatus() { - return pollStatus; - } - - public FirmwareTarget setPollStatus(FirmwarePollStatus pollStatus) { - this.pollStatus = pollStatus; - return this; - } - - public Boolean getRequestAttributes() { - return requestAttributes; - } - - public FirmwareTarget setRequestAttributes(Boolean requestAttributes) { - this.requestAttributes = requestAttributes; - return this; - } - - public Long getTargetType() { - return targetType; - } - - public FirmwareTarget setTargetType(Long targetType) { - this.targetType = targetType; - return this; - } - - public String getTargetTypeName() { - return targetTypeName; - } - - public FirmwareTarget setTargetTypeName(String targetTypeName) { - this.targetTypeName = targetTypeName; - return this; - } - - public Boolean getAutoConfirmActive() { - return autoConfirmActive; - } - - public FirmwareTarget setAutoConfirmActive(Boolean autoConfirmActive) { - this.autoConfirmActive = autoConfirmActive; - return this; + this(controllerId, name, description, null, null, null, null, null, null, null, null, null, null); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java deleted file mode 100644 index 4ca7fd1..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetAssignment.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareTargetAssignment { - protected String id; - protected Long forcetime; - protected Integer weight; - protected Boolean confirmationRequired; - protected String type; - protected FirmwareMaintenanceWindow maintenanceWindow; - - @JsonCreator - public FirmwareTargetAssignment() { - } - - public String getId() { - return id; - } - - public FirmwareTargetAssignment setId(String id) { - this.id = id; - return this; - } - - public Long getForcetime() { - return forcetime; - } - - public FirmwareTargetAssignment setForcetime(Long forcetime) { - this.forcetime = forcetime; - return this; - } - - public Integer getWeight() { - return weight; - } - - public FirmwareTargetAssignment setWeight(Integer weight) { - this.weight = weight; - return this; - } - - public Boolean getConfirmationRequired() { - return confirmationRequired; - } - - public FirmwareTargetAssignment setConfirmationRequired(Boolean confirmationRequired) { - this.confirmationRequired = confirmationRequired; - return this; - } - - public String getType() { - return type; - } - - public FirmwareTargetAssignment setType(String type) { - this.type = type; - return this; - } - - public FirmwareMaintenanceWindow getMaintenanceWindow() { - return maintenanceWindow; - } - - public FirmwareTargetAssignment setMaintenanceWindow(FirmwareMaintenanceWindow maintenanceWindow) { - this.maintenanceWindow = maintenanceWindow; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java deleted file mode 100644 index 3eb27c4..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueries.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareTargetFilterQueries { - protected List content; - protected int total; - protected int size; - - @JsonCreator - protected FirmwareTargetFilterQueries() { - } - - public List getContent() { - return content; - } - - public FirmwareTargetFilterQueries setContent(List content) { - this.content = content; - return this; - } - - public int getTotal() { - return total; - } - - public FirmwareTargetFilterQueries setTotal(int total) { - this.total = total; - return this; - } - - public int getSize() { - return size; - } - - public FirmwareTargetFilterQueries setSize(int size) { - this.size = size; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java deleted file mode 100644 index a2e3456..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQuery.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareTargetFilterQuery { - protected Long id; - protected String name; - protected String query; - protected Long autoAssignDistributionSet; - protected String autoAssignActionType; - protected Integer autoAssignWeight; - protected Boolean confirmationRequired; - - @JsonCreator - protected FirmwareTargetFilterQuery() { - } - - public Long getId() { - return id; - } - - public FirmwareTargetFilterQuery setId(Long id) { - this.id = id; - return this; - } - - public String getName() { - return name; - } - - public FirmwareTargetFilterQuery setName(String name) { - this.name = name; - return this; - } - - public String getQuery() { - return query; - } - - public FirmwareTargetFilterQuery setQuery(String query) { - this.query = query; - return this; - } - - public Long getAutoAssignDistributionSet() { - return autoAssignDistributionSet; - } - - public FirmwareTargetFilterQuery setAutoAssignDistributionSet(Long autoAssignDistributionSet) { - this.autoAssignDistributionSet = autoAssignDistributionSet; - return this; - } - - public String getAutoAssignActionType() { - return autoAssignActionType; - } - - public FirmwareTargetFilterQuery setAutoAssignActionType(String autoAssignActionType) { - this.autoAssignActionType = autoAssignActionType; - return this; - } - - public Integer getAutoAssignWeight() { - return autoAssignWeight; - } - - public FirmwareTargetFilterQuery setAutoAssignWeight(Integer autoAssignWeight) { - this.autoAssignWeight = autoAssignWeight; - return this; - } - - public Boolean getConfirmationRequired() { - return confirmationRequired; - } - - public FirmwareTargetFilterQuery setConfirmationRequired(Boolean confirmationRequired) { - this.confirmationRequired = confirmationRequired; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java deleted file mode 100644 index f658e02..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterQueryRequest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareTargetFilterQueryRequest { - protected String name; - protected String query; - - @JsonCreator - public FirmwareTargetFilterQueryRequest() { - } - - public String getName() { - return name; - } - - public FirmwareTargetFilterQueryRequest setName(String name) { - this.name = name; - return this; - } - - public String getQuery() { - return query; - } - - public FirmwareTargetFilterQueryRequest setQuery(String query) { - this.query = query; - return this; - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java index ca5ce41..9d6169c 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java @@ -19,6 +19,7 @@ */ package org.openremote.extension.hawkbit.model.firmware; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -30,6 +31,7 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -43,23 +45,23 @@ public interface FirmwareTargetFilterResource { @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareTargetFilterQueries getTargetFilters(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getTargetFilters(@BeanParam RequestParams requestParams, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareTargetFilterQuery getTargetFilter(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + Response getTargetFilter(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - FirmwareTargetFilterQuery createTargetFilter(@BeanParam RequestParams requestParams, - FirmwareTargetFilterQueryRequest filter); + Response createTargetFilter(@BeanParam RequestParams requestParams, + JsonNode filter); @DELETE @Path("{id}") @@ -71,17 +73,17 @@ void deleteTargetFilter(@BeanParam RequestParams requestParams, @Path("{id}/autoAssignDS") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareDistributionSet getAutoAssignDS(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + Response getAutoAssignDS(@BeanParam RequestParams requestParams, + @PathParam("id") Long id); @POST @Path("{id}/autoAssignDS") @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - FirmwareTargetFilterQuery setAutoAssignDS(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - FirmwareAutoAssignRequest request); + Response setAutoAssignDS(@BeanParam RequestParams requestParams, + @PathParam("id") Long id, + JsonNode request); @DELETE @Path("{id}/autoAssignDS") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java index 2d8800b..cacd843 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java @@ -27,6 +27,7 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -41,51 +42,51 @@ public interface FirmwareTargetResource { @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareTargets getTargets(@BeanParam RequestParams requestParams, - @QueryParam("q") String query, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getTargets(@BeanParam RequestParams requestParams, + @QueryParam("q") String query, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareTarget getTarget(@BeanParam RequestParams requestParams, @PathParam("id") String id); + Response getTarget(@BeanParam RequestParams requestParams, @PathParam("id") String id); @GET @Path("{id}/metadata") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareMetadataList getMetadata(@BeanParam RequestParams requestParams, @PathParam("id") String id); + Response getMetadata(@BeanParam RequestParams requestParams, @PathParam("id") String id); @GET @Path("{id}/assignedDS") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareDistributionSet getAssignedDs(@BeanParam RequestParams requestParams, @PathParam("id") String id); + Response getAssignedDs(@BeanParam RequestParams requestParams, @PathParam("id") String id); @GET @Path("{id}/installedDS") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareDistributionSet getInstalledDs(@BeanParam RequestParams requestParams, @PathParam("id") String id); + Response getInstalledDs(@BeanParam RequestParams requestParams, @PathParam("id") String id); @GET @Path("{id}/actions") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareActions getActions(@BeanParam RequestParams requestParams, - @PathParam("id") String id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + Response getActions(@BeanParam RequestParams requestParams, + @PathParam("id") String id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); @GET @Path("{id}/actions/{actionId}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - FirmwareAction getAction(@BeanParam RequestParams requestParams, - @PathParam("id") String id, - @PathParam("actionId") Long actionId); + Response getAction(@BeanParam RequestParams requestParams, + @PathParam("id") String id, + @PathParam("actionId") Long actionId); @DELETE @Path("{id}/actions/{actionId}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java deleted file mode 100644 index f6776e9..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargets.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.firmware; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class FirmwareTargets { - protected List content; - protected int total; - protected int size; - - @JsonCreator - protected FirmwareTargets() { - } - - public List getContent() { - return content; - } - - public FirmwareTargets setContent(List content) { - this.content = content; - return this; - } - - public int getTotal() { - return total; - } - - public FirmwareTargets setTotal(int total) { - this.total = total; - return this; - } - - public int getSize() { - return size; - } - - public FirmwareTargets setSize(int size) { - this.size = size; - return this; - } -} From 19504621bb6b67e83bd91faf6e33ff960e889430 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Wed, 13 May 2026 15:37:35 +0200 Subject: [PATCH 07/18] Extend link mapping with name extraction if present --- .../manager/firmware/HawkbitResponse.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java index 255a2c2..3549bc5 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java @@ -33,11 +33,13 @@ class HawkbitResponse { - private static final Map DEFAULT_LINK_ID_FIELDS = Map.of( - "distributionset", "distributionSetId"); + private record LinkMapping(String idField, String nameField) {} + + private static final Map DEFAULT_LINK_MAPPINGS = Map.of( + "distributionset", new LinkMapping("distributionSetId", "distributionSetName")); private final Response response; - private final Map linkIdFields = new LinkedHashMap<>(DEFAULT_LINK_ID_FIELDS); + private final Map linkMappings = new LinkedHashMap<>(DEFAULT_LINK_MAPPINGS); private HawkbitResponse(Response response) { this.response = response; @@ -47,8 +49,8 @@ static HawkbitResponse from(Response response) { return new HawkbitResponse(response); } - HawkbitResponse withLinkId(String rel, String fieldName) { - linkIdFields.put(rel, fieldName); + HawkbitResponse withLinkMapping(String rel, String idField, String nameField) { + linkMappings.put(rel, new LinkMapping(idField, nameField)); return this; } @@ -143,10 +145,15 @@ private void addMappedLinkIds(JsonNode links, ObjectNode target) { return; } - linkIdFields.forEach((rel, fieldName) -> { - Long id = idFromHref(links.path(rel).path("href")); - if (id != null && !target.has(fieldName)) { - target.put(fieldName, id); + linkMappings.forEach((rel, mapping) -> { + JsonNode link = links.path(rel); + Long id = idFromHref(link.path("href")); + if (id != null && !target.has(mapping.idField())) { + target.put(mapping.idField(), id); + } + JsonNode name = link.path("name"); + if (name.isTextual() && !target.has(mapping.nameField())) { + target.put(mapping.nameField(), name.textValue()); } }); } From 6dde76d93c580f816462d4e9fba7a5885ac64bc2 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Thu, 14 May 2026 20:53:00 +0200 Subject: [PATCH 08/18] Clean up, improved proxy request building, and use resteasy multipart --- hawkbit/build.gradle | 1 + .../FirmwareDistributionSetResourceImpl.java | 65 +++-------- ...rmwareDistributionSetTypeResourceImpl.java | 62 +++------- .../firmware/FirmwareRolloutResourceImpl.java | 74 ++++-------- .../manager/firmware/FirmwareService.java | 110 ++++++++++-------- .../FirmwareSoftwareModuleResourceImpl.java | 67 +++-------- ...irmwareSoftwareModuleTypeResourceImpl.java | 40 ++----- .../FirmwareTargetFilterResourceImpl.java | 70 ++++------- .../firmware/FirmwareTargetResourceImpl.java | 68 +++-------- .../manager/firmware/HawkbitResponse.java | 25 +++- .../hawkbit/HawkbitArtifactUploadClient.java | 110 ------------------ .../HawkbitDistributionSetTypesResource.java | 4 +- .../HawkbitDistributionSetsResource.java | 7 +- .../manager/hawkbit/HawkbitMediaType.java | 2 +- .../hawkbit/HawkbitRolloutsResource.java | 4 +- .../HawkbitSoftwareModuleTypesResource.java | 4 +- .../HawkbitSoftwareModulesResource.java | 14 ++- .../hawkbit/HawkbitTargetFiltersResource.java | 7 +- .../model/firmware/FirmwareAutoAssignDS.java | 30 +++++ .../FirmwareDistributionSetAssignment.java | 31 +++++ .../FirmwareDistributionSetCreate.java | 31 +++++ .../FirmwareDistributionSetResource.java | 5 +- .../FirmwareDistributionSetTypeCreate.java | 31 +++++ .../FirmwareDistributionSetTypeResource.java | 3 +- .../firmware/FirmwareModuleReference.java | 26 +++++ .../model/firmware/FirmwareRolloutAction.java | 26 +++++ .../firmware/FirmwareRolloutCondition.java | 26 +++++ .../model/firmware/FirmwareRolloutCreate.java | 40 +++++++ .../firmware/FirmwareRolloutResource.java | 3 +- .../FirmwareSoftwareModuleCreate.java | 32 +++++ .../FirmwareSoftwareModuleResource.java | 3 +- .../FirmwareSoftwareModuleTypeCreate.java | 30 +++++ .../FirmwareSoftwareModuleTypeResource.java | 3 +- .../firmware/FirmwareTargetFilterCreate.java | 26 +++++ .../FirmwareTargetFilterResource.java | 5 +- 35 files changed, 576 insertions(+), 509 deletions(-) delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignDS.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetCreate.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeCreate.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModuleReference.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCreate.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleCreate.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeCreate.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterCreate.java diff --git a/hawkbit/build.gradle b/hawkbit/build.gradle index 7a4b24c..58105f2 100644 --- a/hawkbit/build.gradle +++ b/hawkbit/build.gradle @@ -13,6 +13,7 @@ dependencies { api "org.jboss.resteasy:resteasy-client-api:$resteasyVersion" api "org.jboss.resteasy:resteasy-jaxb-provider:$resteasyVersion" + api "org.jboss.resteasy:resteasy-multipart-provider:$resteasyVersion" testImplementation "io.openremote:openremote-test:$openremoteVersion" } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java index a13dd8d..b6fed9c 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java @@ -19,16 +19,14 @@ */ package org.openremote.extension.hawkbit.manager.firmware; -import com.fasterxml.jackson.databind.JsonNode; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetAssignment; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetCreate; import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetResource; public class FirmwareDistributionSetResourceImpl extends ManagerWebResource @@ -44,63 +42,38 @@ public FirmwareDistributionSetResourceImpl(TimerService timerService, ManagerIde @Override public Response createDistributionSet(RequestParams requestParams, - JsonNode distributionSet) { - try { - return HawkbitResponse.from(firmwareService.distributionSetsResource.create(distributionSet)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to create firmware distribution set", e, - Response.Status.BAD_GATEWAY); - } + FirmwareDistributionSetCreate distributionSet) { + return HawkbitResponse.proxy("Failed to create firmware distribution set", + () -> firmwareService.distributionSetsResource.create( + new FirmwareDistributionSetCreate[] { distributionSet })).asResource(); } @Override public Response assignDistributionSet(RequestParams requestParams, Long id, Boolean offline, - JsonNode targets) { - try { - if (targets == null || !targets.isArray() || targets.isEmpty()) { - throw new WebApplicationException("Assignment requires at least one target", Response.Status.BAD_REQUEST); - } - - return HawkbitResponse.from(firmwareService.distributionSetsResource.assignTargets(id, offline, targets)) - .asResource(); - } catch (WebApplicationException e) { - throw e; - } catch (Exception e) { - throw new WebApplicationException("Failed to assign firmware distribution set '" + id + "'", e, - Response.Status.BAD_GATEWAY); + FirmwareDistributionSetAssignment[] targets) { + if (targets == null || targets.length == 0) { + throw new WebApplicationException("Assignment requires at least one target", Response.Status.BAD_REQUEST); } + return HawkbitResponse.proxy("Failed to assign firmware distribution set '" + id + "'", + () -> firmwareService.distributionSetsResource.assignTargets(id, offline, targets)).asResource(); } @Override public Response getDistributionSets(RequestParams requestParams, Integer offset, Integer limit) { - try { - return HawkbitResponse.from(firmwareService.distributionSetsResource.getDistributionSets(offset, limit)) - .asPage(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware distribution sets", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware distribution sets", + () -> firmwareService.distributionSetsResource.getDistributionSets(offset, limit)).asPage(); } @Override public Response getDistributionSet(RequestParams requestParams, Long id) { - try { - return HawkbitResponse.from(firmwareService.distributionSetsResource.get(id)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware distribution set '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware distribution set '" + id + "'", + () -> firmwareService.distributionSetsResource.get(id)).asResource(); } - @DELETE - @Path("{id}") - public void deleteDistributionSet(RequestParams requestParams, @PathParam("id") Long id) { - try { - firmwareService.distributionSetsResource.delete(id); - } catch (Exception e) { - throw new WebApplicationException("Failed to delete firmware distribution set '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + @Override + public void deleteDistributionSet(RequestParams requestParams, Long id) { + HawkbitResponse.proxy("Failed to delete firmware distribution set '" + id + "'", + () -> firmwareService.distributionSetsResource.delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java index 1e923bc..d4742b4 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java @@ -19,13 +19,12 @@ */ package org.openremote.extension.hawkbit.manager.firmware; -import com.fasterxml.jackson.databind.JsonNode; -import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypeCreate; import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypeResource; public class FirmwareDistributionSetTypeResourceImpl extends ManagerWebResource @@ -42,71 +41,44 @@ public FirmwareDistributionSetTypeResourceImpl(TimerService timerService, @Override public Response createDistributionSetType(RequestParams requestParams, - JsonNode distributionSetType) { - try { - return HawkbitResponse.from(firmwareService.distributionSetTypesResource.create(distributionSetType)) - .asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to create firmware distribution set type", e, - Response.Status.BAD_GATEWAY); - } + FirmwareDistributionSetTypeCreate distributionSetType) { + return HawkbitResponse.proxy("Failed to create firmware distribution set type", + () -> firmwareService.distributionSetTypesResource.create( + new FirmwareDistributionSetTypeCreate[] { distributionSetType })).asResource(); } @Override public Response getDistributionSetTypes(RequestParams requestParams, Integer offset, Integer limit) { - try { - return HawkbitResponse.from(firmwareService.distributionSetTypesResource.getDistributionSetTypes(offset, limit)) - .asPage(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware distribution set types", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware distribution set types", + () -> firmwareService.distributionSetTypesResource.getDistributionSetTypes(offset, limit)).asPage(); } @Override public Response getDistributionSetType(RequestParams requestParams, Long id) { - try { - return HawkbitResponse.from(firmwareService.distributionSetTypesResource.get(id)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware distribution set type '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware distribution set type '" + id + "'", + () -> firmwareService.distributionSetTypesResource.get(id)).asResource(); } @Override public Response getMandatoryModuleTypes(RequestParams requestParams, Long id, Integer offset, Integer limit) { - try { - return HawkbitResponse.from(firmwareService.distributionSetTypesResource.getMandatoryModuleTypes(id, offset, limit)) - .asPage(); - } catch (Exception e) { - throw new WebApplicationException( - "Failed to retrieve mandatory module types for firmware distribution set type '" + id + "'", - e, Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy( + "Failed to retrieve mandatory module types for firmware distribution set type '" + id + "'", + () -> firmwareService.distributionSetTypesResource.getMandatoryModuleTypes(id, offset, limit)).asPage(); } @Override public Response getOptionalModuleTypes(RequestParams requestParams, Long id, Integer offset, Integer limit) { - try { - return HawkbitResponse.from(firmwareService.distributionSetTypesResource.getOptionalModuleTypes(id, offset, limit)) - .asPage(); - } catch (Exception e) { - throw new WebApplicationException( - "Failed to retrieve optional module types for firmware distribution set type '" + id + "'", - e, Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy( + "Failed to retrieve optional module types for firmware distribution set type '" + id + "'", + () -> firmwareService.distributionSetTypesResource.getOptionalModuleTypes(id, offset, limit)).asPage(); } @Override public void deleteDistributionSetType(RequestParams requestParams, Long id) { - try { - firmwareService.distributionSetTypesResource.delete(id); - } catch (Exception e) { - throw new WebApplicationException("Failed to delete firmware distribution set type '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + HawkbitResponse.proxy("Failed to delete firmware distribution set type '" + id + "'", + () -> firmwareService.distributionSetTypesResource.delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java index 644e15c..4130940 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java @@ -19,12 +19,11 @@ */ package org.openremote.extension.hawkbit.manager.firmware; -import com.fasterxml.jackson.databind.JsonNode; -import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutCreate; import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutResource; import org.openremote.model.http.RequestParams; @@ -41,85 +40,52 @@ public FirmwareRolloutResourceImpl(TimerService timerService, ManagerIdentitySer @Override public Response getRollouts(RequestParams requestParams, Integer offset, Integer limit) { - try { - // Request full representation so totalTargetsPerStatus and totalGroups are populated; hawkBit defaults to compact. - return HawkbitResponse.from(firmwareService.rolloutsResource.getRollouts(offset, limit, "full")).asPage(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware rollouts", e, - Response.Status.BAD_GATEWAY); - } + // Request full representation so totalTargetsPerStatus and totalGroups are populated; hawkBit defaults to compact. + return HawkbitResponse.proxy("Failed to retrieve firmware rollouts", + () -> firmwareService.rolloutsResource.getRollouts(offset, limit, "full")).asPage(); } @Override public Response getRollout(RequestParams requestParams, Long id) { - try { - return HawkbitResponse.from(firmwareService.rolloutsResource.get(id)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware rollout '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware rollout '" + id + "'", + () -> firmwareService.rolloutsResource.get(id)).asResource(); } @Override - public Response createRollout(RequestParams requestParams, JsonNode rollout) { - try { - return HawkbitResponse.from(firmwareService.rolloutsResource.create(rollout)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to create firmware rollout", e, - Response.Status.BAD_GATEWAY); - } + public Response createRollout(RequestParams requestParams, FirmwareRolloutCreate rollout) { + return HawkbitResponse.proxy("Failed to create firmware rollout", + () -> firmwareService.rolloutsResource.create(rollout)).asResource(); } @Override public void deleteRollout(RequestParams requestParams, Long id) { - try { - firmwareService.rolloutsResource.delete(id); - } catch (Exception e) { - throw new WebApplicationException("Failed to delete firmware rollout '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + HawkbitResponse.proxy("Failed to delete firmware rollout '" + id + "'", + () -> firmwareService.rolloutsResource.delete(id)); } @Override public Response startRollout(RequestParams requestParams, Long id) { - try { - return HawkbitResponse.from(firmwareService.rolloutsResource.start(id)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to start firmware rollout '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to start firmware rollout '" + id + "'", + () -> firmwareService.rolloutsResource.start(id)).asResource(); } @Override public void pauseRollout(RequestParams requestParams, Long id) { - try { - firmwareService.rolloutsResource.pause(id); - } catch (Exception e) { - throw new WebApplicationException("Failed to pause firmware rollout '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + HawkbitResponse.proxy("Failed to pause firmware rollout '" + id + "'", + () -> firmwareService.rolloutsResource.pause(id)); } @Override public Response getRolloutGroups(RequestParams requestParams, Long id, Integer offset, Integer limit) { - try { - return HawkbitResponse.from(firmwareService.rolloutsResource.getRolloutGroups(id, offset, limit, "full")) - .asPage(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve groups for rollout '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve groups for rollout '" + id + "'", + () -> firmwareService.rolloutsResource.getRolloutGroups(id, offset, limit, "full")).asPage(); } @Override public Response getRolloutGroup(RequestParams requestParams, Long id, Long groupId) { - try { - return HawkbitResponse.from(firmwareService.rolloutsResource.getRolloutGroup(id, groupId)).asResource(); - } catch (Exception e) { - throw new WebApplicationException( - "Failed to retrieve group '" + groupId + "' for rollout '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy( + "Failed to retrieve group '" + groupId + "' for rollout '" + id + "'", + () -> firmwareService.rolloutsResource.getRolloutGroup(id, groupId)).asResource(); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java index e015fd1..b012d48 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java @@ -1,5 +1,5 @@ /* - * Copyright 2021, OpenRemote Inc. + * Copyright 2025, OpenRemote Inc. * * See the CONTRIBUTORS.txt file in the distribution for a * full listing of individual contributors. @@ -25,7 +25,6 @@ import static org.openremote.model.syslog.SyslogCategory.API; import static org.openremote.model.util.MapAccess.getString; -import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; @@ -38,18 +37,20 @@ import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.client.ClientRequestFilter; import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; import org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider; +import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataWriter; import org.openremote.container.timer.TimerService; import org.openremote.container.web.WebClient; import org.openremote.container.web.WebTargetBuilder; import org.openremote.manager.asset.AssetProcessingService; import org.openremote.manager.event.ClientEventService; import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitArtifactUploadClient; import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitBasicAuth; import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitDistributionSetsResource; import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitDistributionSetTypesResource; @@ -88,9 +89,9 @@ public class FirmwareService implements ContainerService { public static final String HAWKBIT_MANAGEMENT_API_URL = "HAWKBIT_MANAGEMENT_API_URL"; public static final String HAWKBIT_MANAGEMENT_API_URL_DEFAULT = "http://localhost:8083/hawkbit/rest/v1"; - protected static final Logger LOG = SyslogCategory.getLogger(API, FirmwareService.class); + private static final Logger LOG = SyslogCategory.getLogger(API, FirmwareService.class); - protected static ResteasyClient client; + protected ResteasyClient client; protected String hawkbitRealm; protected ClientEventService clientEventService; @@ -105,18 +106,6 @@ public class FirmwareService implements ContainerService { protected HawkbitSoftwareModuleTypesResource softwareModuleTypesResource; protected HawkbitRolloutsResource rolloutsResource; protected HawkbitTargetFiltersResource targetFiltersResource; - protected HawkbitArtifactUploadClient artifactUploadClient; - - static { - client = createClient(org.openremote.container.Container.EXECUTOR, CONNECTION_POOL_SIZE, - CONNECTION_TIMEOUT_MILLISECONDS, resteasyClientBuilder -> { - WebClient.registerDefaults((ResteasyClientBuilderImpl) resteasyClientBuilder); - ResteasyJackson2Provider provider = new ResteasyJackson2Provider(); - provider.setMapper(ValueUtil.JSON); - resteasyClientBuilder.register(provider); - return resteasyClientBuilder; - }); - } @Override public void init(Container container) throws Exception { @@ -172,7 +161,17 @@ public void start(Container container) throws Exception { hawkbitRealm = getString(container.getConfig(), HAWKBIT_REALM, HAWKBIT_REALM_DEFAULT); LOG.info(HAWKBIT_MANAGEMENT_API_URL + "=" + uri); - + + client = createClient(org.openremote.container.Container.EXECUTOR, CONNECTION_POOL_SIZE, + CONNECTION_TIMEOUT_MILLISECONDS, resteasyClientBuilder -> { + WebClient.registerDefaults((ResteasyClientBuilderImpl) resteasyClientBuilder); + ResteasyJackson2Provider provider = new ResteasyJackson2Provider(); + provider.setMapper(ValueUtil.JSON); + resteasyClientBuilder.register(provider); + resteasyClientBuilder.register(MultipartFormDataWriter.class); + return resteasyClientBuilder; + }); + ResteasyWebTarget webTarget = new WebTargetBuilder(client, uri).build(); webTarget.register((ClientRequestFilter) requestContext -> requestContext.getHeaders().putSingle( HttpHeaders.AUTHORIZATION, @@ -187,10 +186,6 @@ public void start(Container container) throws Exception { rolloutsResource = webTarget.proxy(HawkbitRolloutsResource.class); targetFiltersResource = webTarget.proxy(HawkbitTargetFiltersResource.class); - // Artifact upload uses raw multipart forwarding because Hawkbit expects - // multipart/form-data for this endpoint. - artifactUploadClient = new HawkbitArtifactUploadClient(uri, hawkbitUsername, hawkbitPassword); - // Subscribe on asset events clientEventService.addSubscription( AssetEvent.class, @@ -213,10 +208,15 @@ public void stop(Container container) throws Exception { } public Response uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream inputStream, - String originalFilename, String filename) - throws IOException, InterruptedException { - return HawkbitResponse.from(artifactUploadClient.uploadSoftwareModuleArtifact(softwareModuleId, inputStream, - originalFilename, filename)).asResource(); + String originalFilename, String filename) { + String effectiveFilename = TextUtil.isNullOrEmpty(filename) ? originalFilename : filename; + String uploadFilename = TextUtil.isNullOrEmpty(effectiveFilename) ? "artifact.bin" : effectiveFilename; + MultipartFormDataOutput form = new MultipartFormDataOutput(); + form.addFormData("file", inputStream, MediaType.APPLICATION_OCTET_STREAM_TYPE, uploadFilename); + return HawkbitResponse.from(softwareModulesResource.uploadArtifact(softwareModuleId, + TextUtil.isNullOrEmpty(effectiveFilename) ? null : effectiveFilename, + form)) + .asResource(); } private void onAssetChange(AssetEvent assetEvent) { @@ -249,10 +249,10 @@ private void handleAttributeChange(AttributeEvent attributeEvent) { return; } - attributeEvent.getValue().ifPresent(value -> syncFirmwareTargetMetadataValue( + syncFirmwareTargetMetadataValue( attributeEvent.getId(), attributeEvent.getName(), - value)); + attributeEvent.getValue().orElse(null)); } private void handleAssetChange(AssetEvent assetEvent) { @@ -275,21 +275,24 @@ private void handleAssetChange(AssetEvent assetEvent) { shouldUpdateFirmwareTargetInfo = createFirmwareTarget(buildFirmwareTarget(asset)); break; case UPDATE: - LOG.info("Checking hawkbit target for update asset id=" + asset.getId()); + LOG.fine("Checking hawkbit target for update asset id=" + asset.getId()); + FirmwareTarget existingTarget; try { - FirmwareTarget existingTarget = getFirmwareTarget(controllerId); - if (existingTarget != null) { - LOG.info("hawkbit target already exists so nothing to do id=" + controllerId); - shouldUpdateFirmwareTargetInfo = true; - break; - } + existingTarget = getFirmwareTarget(controllerId); } catch (Exception e) { - LOG.log(Level.FINE, "Failed to load hawkbit target id=" + controllerId - + ", trying create instead", e); + LOG.log(Level.WARNING, "Failed to query hawkbit target id=" + controllerId + + ", skipping update to avoid spurious create", e); + break; + } + + if (existingTarget != null) { + LOG.fine("hawkbit target already exists id=" + controllerId); + shouldUpdateFirmwareTargetInfo = true; + break; } + LOG.info("hawkbit target missing for asset id=" + asset.getId() + ", creating it now"); if (createFirmwareTarget(buildFirmwareTarget(asset))) { - LOG.info("hawkbit target missing for asset id=" + asset.getId() + ", creating it now"); shouldUpdateFirmwareTargetInfo = true; } break; @@ -313,8 +316,7 @@ private void updateFirmwareTargetMetadata(Asset asset) { continue; } - attribute.getValue().ifPresent(value -> - syncFirmwareTargetMetadataValue(controllerId, attribute.getName(), value)); + syncFirmwareTargetMetadataValue(controllerId, attribute.getName(), attribute.getValue().orElse(null)); } } @@ -343,7 +345,8 @@ private boolean hasFirmwareMetadata(MetaMap meta) { } private void syncFirmwareTargetMetadataValue(String controllerId, String key, Object value) { - if (value == null) { + if (isAttributeEmptyOrNull(value)) { + deleteFirmwareTargetMetadata(controllerId, key); return; } @@ -357,6 +360,12 @@ private void syncFirmwareTargetMetadataValue(String controllerId, String key, Ob updateFirmwareTargetMetadata(controllerId, key, metadataValue.get()); } + private boolean isAttributeEmptyOrNull(Object value) { + return value == null || ValueUtil.getStringCoerced(value) + .map(String::isEmpty) + .orElse(false); + } + private void updateFirmwareTargetMetadata(String controllerId, String key, String value) { try { targetsResource.updateMetadata(controllerId, key, new FirmwareMetadataUpdate(value)); @@ -384,9 +393,11 @@ private void deleteFirmwareTargetMetadata(String controllerId, String key) { } private Optional> getFirmwareTargetInfoDescriptor(Asset asset) { + // TODO: Decide whether firmwareTarget should also be honored when defined on + // an asset attribute instance instead of only on the asset type descriptor. Optional assetTypeInfo = ValueUtil.getAssetInfo(asset.getType()); if (assetTypeInfo.isEmpty()) { - LOG.warning("Cannot resolve asset type info for asset type '" + asset.getType() + "'"); + LOG.fine("Cannot resolve asset type info for asset type '" + asset.getType() + "'"); return Optional.empty(); } @@ -465,11 +476,18 @@ private void updateFirmwareTargetInfo(AssetEvent assetEvent) { Map firmwareTargetInfo = new LinkedHashMap<>(); firmwareTargetInfo.put("controllerId", firmwareTarget.controllerId()); firmwareTargetInfo.put("securityToken", firmwareTarget.securityToken()); + String newValueJson = ValueUtil.asJSON(firmwareTargetInfo).orElse(null); + + String existingValueJson = asset.getAttribute(attributeName) + .flatMap(attr -> attr.getValue(String.class)) + .orElse(null); + if (Objects.equals(existingValueJson, newValueJson)) { + LOG.fine("Firmware target info attribute up to date for asset id=" + asset.getId()); + return; + } + assetProcessingService.sendAttributeEvent( - new AttributeEvent( - asset.getId(), - attributeName, - ValueUtil.asJSON(firmwareTargetInfo).orElse(null)), + new AttributeEvent(asset.getId(), attributeName, newValueJson), getClass().getSimpleName()); LOG.info("Updated firmware target info attribute for asset id=" + asset.getId() + ", controllerId=" + firmwareTarget.controllerId()); diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java index b00f97e..60156ee 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java @@ -19,22 +19,14 @@ */ package org.openremote.extension.hawkbit.manager.firmware; -import com.fasterxml.jackson.databind.JsonNode; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.EntityPart; -import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleCreate; import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleResource; import java.io.InputStream; @@ -53,52 +45,34 @@ public FirmwareSoftwareModuleResourceImpl(TimerService timerService, ManagerIden @Override public Response createSoftwareModule(RequestParams requestParams, - JsonNode softwareModule) { - try { - return HawkbitResponse.from(firmwareService.softwareModulesResource.create(softwareModule)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to create firmware software module", e, - Response.Status.BAD_GATEWAY); - } + FirmwareSoftwareModuleCreate softwareModule) { + return HawkbitResponse.proxy("Failed to create firmware software module", + () -> firmwareService.softwareModulesResource.create( + new FirmwareSoftwareModuleCreate[] { softwareModule })).asResource(); } @Override public Response getSoftwareModules(RequestParams requestParams, Integer offset, Integer limit) { - try { - return HawkbitResponse.from(firmwareService.softwareModulesResource.getSoftwareModules(offset, limit)).asPage(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware software modules", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware software modules", + () -> firmwareService.softwareModulesResource.getSoftwareModules(offset, limit)).asPage(); } @Override public Response getSoftwareModule(RequestParams requestParams, Long id) { - try { - return HawkbitResponse.from(firmwareService.softwareModulesResource.get(id)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware software module '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware software module '" + id + "'", + () -> firmwareService.softwareModulesResource.get(id)).asResource(); } @Override public Response getSoftwareModuleArtifacts(RequestParams requestParams, Long id) { - try { - return HawkbitResponse.from(firmwareService.softwareModulesResource.getArtifacts(id)).asPage(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve artifacts for firmware software module '" + id + "'", - e, Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve artifacts for firmware software module '" + id + "'", + () -> firmwareService.softwareModulesResource.getArtifacts(id)).asPage(); } - @POST - @Path("{id}/artifacts") - @Consumes(MediaType.MULTIPART_FORM_DATA) - @Produces(MediaType.APPLICATION_JSON) + @Override public Response uploadSoftwareModuleArtifact(RequestParams requestParams, - @PathParam("id") Long id, - @QueryParam("filename") String filename, + Long id, + String filename, List parts) { try { EntityPart filePart = parts == null ? null : parts.stream() @@ -120,14 +94,9 @@ public Response uploadSoftwareModuleArtifact(RequestParams requestParams, } } - @DELETE - @Path("{id}") - public void deleteSoftwareModule(RequestParams requestParams, @PathParam("id") Long id) { - try { - firmwareService.softwareModulesResource.delete(id); - } catch (Exception e) { - throw new WebApplicationException("Failed to delete firmware software module '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + @Override + public void deleteSoftwareModule(RequestParams requestParams, Long id) { + HawkbitResponse.proxy("Failed to delete firmware software module '" + id + "'", + () -> firmwareService.softwareModulesResource.delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java index 61171a5..310b0de 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java @@ -19,13 +19,12 @@ */ package org.openremote.extension.hawkbit.manager.firmware; -import com.fasterxml.jackson.databind.JsonNode; -import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypeCreate; import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypeResource; public class FirmwareSoftwareModuleTypeResourceImpl extends ManagerWebResource @@ -41,45 +40,28 @@ public FirmwareSoftwareModuleTypeResourceImpl(TimerService timerService, Manager @Override public Response createSoftwareModuleType(RequestParams requestParams, - JsonNode softwareModuleType) { - try { - return HawkbitResponse.from(firmwareService.softwareModuleTypesResource.create(softwareModuleType)) - .asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to create firmware software module type", e, - Response.Status.BAD_GATEWAY); - } + FirmwareSoftwareModuleTypeCreate softwareModuleType) { + return HawkbitResponse.proxy("Failed to create firmware software module type", + () -> firmwareService.softwareModuleTypesResource.create( + new FirmwareSoftwareModuleTypeCreate[] { softwareModuleType })).asResource(); } @Override public Response getSoftwareModuleTypes(RequestParams requestParams, Integer offset, Integer limit) { - try { - return HawkbitResponse.from(firmwareService.softwareModuleTypesResource.getSoftwareModuleTypes(offset, limit)) - .asPage(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware software module types", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware software module types", + () -> firmwareService.softwareModuleTypesResource.getSoftwareModuleTypes(offset, limit)).asPage(); } @Override public Response getSoftwareModuleType(RequestParams requestParams, Long id) { - try { - return HawkbitResponse.from(firmwareService.softwareModuleTypesResource.get(id)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware software module type '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware software module type '" + id + "'", + () -> firmwareService.softwareModuleTypesResource.get(id)).asResource(); } @Override public void deleteSoftwareModuleType(RequestParams requestParams, Long id) { - try { - firmwareService.softwareModuleTypesResource.delete(id); - } catch (Exception e) { - throw new WebApplicationException("Failed to delete firmware software module type '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + HawkbitResponse.proxy("Failed to delete firmware software module type '" + id + "'", + () -> firmwareService.softwareModuleTypesResource.delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java index 0d0122c..e216937 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java @@ -19,12 +19,12 @@ */ package org.openremote.extension.hawkbit.manager.firmware; -import com.fasterxml.jackson.databind.JsonNode; -import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; +import org.openremote.extension.hawkbit.model.firmware.FirmwareAutoAssignDS; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterCreate; import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterResource; import org.openremote.model.http.RequestParams; @@ -41,76 +41,48 @@ public FirmwareTargetFilterResourceImpl(TimerService timerService, ManagerIdenti @Override public Response getTargetFilters(RequestParams requestParams, Integer offset, Integer limit) { - try { - return HawkbitResponse.from(firmwareService.targetFiltersResource.getTargetFilters(offset, limit)).asPage(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware target filters", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware target filters", + () -> firmwareService.targetFiltersResource.getTargetFilters(offset, limit)).asPage(); } @Override public Response getTargetFilter(RequestParams requestParams, Long id) { - try { - return HawkbitResponse.from(firmwareService.targetFiltersResource.get(id)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware target filter '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware target filter '" + id + "'", + () -> firmwareService.targetFiltersResource.get(id)).asResource(); } @Override public Response createTargetFilter(RequestParams requestParams, - JsonNode filter) { - try { - return HawkbitResponse.from(firmwareService.targetFiltersResource.create(filter)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to create firmware target filter", e, - Response.Status.BAD_GATEWAY); - } + FirmwareTargetFilterCreate filter) { + return HawkbitResponse.proxy("Failed to create firmware target filter", + () -> firmwareService.targetFiltersResource.create(filter)).asResource(); } @Override public void deleteTargetFilter(RequestParams requestParams, Long id) { - try { - firmwareService.targetFiltersResource.delete(id); - } catch (Exception e) { - throw new WebApplicationException("Failed to delete firmware target filter '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + HawkbitResponse.proxy("Failed to delete firmware target filter '" + id + "'", + () -> firmwareService.targetFiltersResource.delete(id)); } @Override public Response getAutoAssignDS(RequestParams requestParams, Long id) { - try { - return HawkbitResponse.from(firmwareService.targetFiltersResource.getAutoAssignDS(id)).asResource(); - } catch (Exception e) { - throw new WebApplicationException( - "Failed to retrieve auto assign distribution set for filter '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy( + "Failed to retrieve auto assign distribution set for filter '" + id + "'", + () -> firmwareService.targetFiltersResource.getAutoAssignDS(id)).asResource(); } @Override public Response setAutoAssignDS(RequestParams requestParams, Long id, - JsonNode request) { - try { - return HawkbitResponse.from(firmwareService.targetFiltersResource.setAutoAssignDS(id, request)).asResource(); - } catch (Exception e) { - throw new WebApplicationException( - "Failed to set auto assign distribution set for filter '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + FirmwareAutoAssignDS request) { + return HawkbitResponse.proxy( + "Failed to set auto assign distribution set for filter '" + id + "'", + () -> firmwareService.targetFiltersResource.setAutoAssignDS(id, request)).asResource(); } @Override public void deleteAutoAssignDS(RequestParams requestParams, Long id) { - try { - firmwareService.targetFiltersResource.deleteAutoAssignDS(id); - } catch (Exception e) { - throw new WebApplicationException( - "Failed to remove auto assign distribution set from filter '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + HawkbitResponse.proxy( + "Failed to remove auto assign distribution set from filter '" + id + "'", + () -> firmwareService.targetFiltersResource.deleteAutoAssignDS(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java index fe92a92..3f205b9 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.manager.firmware; -import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.manager.security.ManagerIdentityService; @@ -39,82 +38,51 @@ public FirmwareTargetResourceImpl(TimerService timerService, ManagerIdentityServ @Override public Response getTargets(RequestParams requestParams, String query, Integer offset, Integer limit) { - try { - return HawkbitResponse.from(firmwareService.targetsResource.getTargets(query, offset, limit)).asPage(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware targets", e, Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware targets", + () -> firmwareService.targetsResource.getTargets(query, offset, limit)).asPage(); } @Override public Response getTarget(RequestParams requestParams, String id) { - try { - return HawkbitResponse.from(firmwareService.targetsResource.get(id)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve firmware target '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve firmware target '" + id + "'", + () -> firmwareService.targetsResource.get(id)).asResource(); } @Override public Response getMetadata(RequestParams requestParams, String id) { - try { - return HawkbitResponse.from(firmwareService.targetsResource.getMetadata(id)).asPage(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve metadata for firmware target '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve metadata for firmware target '" + id + "'", + () -> firmwareService.targetsResource.getMetadata(id)).asPage(); } @Override public Response getAssignedDs(RequestParams requestParams, String id) { - try { - return HawkbitResponse.from(firmwareService.targetsResource.getAssignedDs(id)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve assigned DS for firmware target '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve assigned DS for firmware target '" + id + "'", + () -> firmwareService.targetsResource.getAssignedDs(id)).asResource(); } @Override public Response getInstalledDs(RequestParams requestParams, String id) { - try { - return HawkbitResponse.from(firmwareService.targetsResource.getInstalledDs(id)).asResource(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve installed DS for firmware target '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve installed DS for firmware target '" + id + "'", + () -> firmwareService.targetsResource.getInstalledDs(id)).asResource(); } @Override public Response getActions(RequestParams requestParams, String id, Integer offset, Integer limit) { - try { - return HawkbitResponse.from(firmwareService.targetsResource.getActions(id, offset, limit)).asPage(); - } catch (Exception e) { - throw new WebApplicationException("Failed to retrieve actions for firmware target '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy("Failed to retrieve actions for firmware target '" + id + "'", + () -> firmwareService.targetsResource.getActions(id, offset, limit)).asPage(); } @Override public Response getAction(RequestParams requestParams, String id, Long actionId) { - try { - return HawkbitResponse.from(firmwareService.targetsResource.getAction(id, actionId)).asResource(); - } catch (Exception e) { - throw new WebApplicationException( - "Failed to retrieve action '" + actionId + "' for firmware target '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + return HawkbitResponse.proxy( + "Failed to retrieve action '" + actionId + "' for firmware target '" + id + "'", + () -> firmwareService.targetsResource.getAction(id, actionId)).asResource(); } @Override public void cancelAction(RequestParams requestParams, String id, Long actionId, Boolean force) { - try { - firmwareService.targetsResource.cancelAction(id, actionId, force); - } catch (Exception e) { - throw new WebApplicationException( - "Failed to cancel action '" + actionId + "' for firmware target '" + id + "'", e, - Response.Status.BAD_GATEWAY); - } + HawkbitResponse.proxy( + "Failed to cancel action '" + actionId + "' for firmware target '" + id + "'", + () -> firmwareService.targetsResource.cancelAction(id, actionId, force)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java index 3549bc5..46e7267 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2026, OpenRemote Inc. + * Copyright 2025, OpenRemote Inc. * * See the CONTRIBUTORS.txt file in the distribution for a * full listing of individual contributors. @@ -30,9 +30,30 @@ import java.util.LinkedHashMap; import java.util.Map; +import java.util.function.Supplier; class HawkbitResponse { + static HawkbitResponse proxy(String errorMessage, Supplier call) { + try { + return from(call.get()); + } catch (WebApplicationException e) { + throw e; + } catch (Exception e) { + throw new WebApplicationException(errorMessage, e, Response.Status.BAD_GATEWAY); + } + } + + static void proxy(String errorMessage, Runnable call) { + try { + call.run(); + } catch (WebApplicationException e) { + throw e; + } catch (Exception e) { + throw new WebApplicationException(errorMessage, e, Response.Status.BAD_GATEWAY); + } + } + private record LinkMapping(String idField, String nameField) {} private static final Map DEFAULT_LINK_MAPPINGS = Map.of( @@ -166,7 +187,7 @@ private static Long idFromHref(JsonNode hrefNode) { String href = hrefNode.textValue(); int end = href.endsWith("/") ? href.length() - 1 : href.length(); int start = href.lastIndexOf('/', end - 1) + 1; - if (start < 0 || start >= end) { + if (start >= end) { return null; } try { diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java deleted file mode 100644 index 3806dd7..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitArtifactUploadClient.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.manager.hawkbit; - -import jakarta.ws.rs.core.Response; -import org.openremote.model.util.TextUtil; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URLEncoder; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; -import java.util.UUID; - -import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; - -public class HawkbitArtifactUploadClient { - - protected final URI hawkbitManagementUri; - protected final String hawkbitUsername; - protected final String hawkbitPassword; - - public HawkbitArtifactUploadClient(URI hawkbitManagementUri, String hawkbitUsername, String hawkbitPassword) { - this.hawkbitManagementUri = hawkbitManagementUri; - this.hawkbitUsername = hawkbitUsername; - this.hawkbitPassword = hawkbitPassword; - } - - public Response uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream inputStream, - String originalFilename, String filename) - throws IOException, InterruptedException { - String effectiveFilename = TextUtil.isNullOrEmpty(filename) ? originalFilename : filename; - String boundary = "----OpenRemoteBoundary" + UUID.randomUUID(); - byte[] payload = buildMultipartPayload(boundary, inputStream.readAllBytes(), effectiveFilename); - - HttpRequest request = HttpRequest.newBuilder( - buildArtifactUploadUri(softwareModuleId, effectiveFilename)) - .header("Authorization", HawkbitBasicAuth.buildAuthorizationHeader(hawkbitUsername, hawkbitPassword)) - .header("Accept", APPLICATION_HAL_JSON) - .header("Content-Type", "multipart/form-data; boundary=" + boundary) - .POST(HttpRequest.BodyPublishers.ofByteArray(payload)) - .build(); - - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); - - return Response.status(response.statusCode()) - .type(response.headers().firstValue("content-type").orElse(APPLICATION_HAL_JSON)) - .entity(response.body()) - .build(); - } - - protected URI buildArtifactUploadUri(Long softwareModuleId, String filename) { - StringBuilder uriBuilder = new StringBuilder(hawkbitManagementUri.toString()) - .append("/softwaremodules/") - .append(softwareModuleId) - .append("/artifacts"); - - appendQueryParam(uriBuilder, "filename", filename, true); - return URI.create(uriBuilder.toString()); - } - - protected boolean appendQueryParam(StringBuilder uriBuilder, String name, String value, boolean first) { - if (TextUtil.isNullOrEmpty(value)) { - return first; - } - - uriBuilder.append(first ? '?' : '&') - .append(name) - .append('=') - .append(URLEncoder.encode(value, StandardCharsets.UTF_8)); - return false; - } - - protected byte[] buildMultipartPayload(String boundary, byte[] fileBytes, String filename) throws IOException { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - outputStream.write(("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8)); - outputStream.write(("Content-Disposition: form-data; name=\"file\"; filename=\"" + escapeQuoted(filename) - + "\"\r\n").getBytes(StandardCharsets.UTF_8)); - outputStream.write("Content-Type: application/octet-stream\r\n\r\n".getBytes(StandardCharsets.UTF_8)); - outputStream.write(fileBytes); - outputStream.write(("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); - return outputStream.toByteArray(); - } - - protected String escapeQuoted(String value) { - return value == null ? "artifact.bin" : value.replace("\"", "\\\""); - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java index 92f663d..c6cbb1e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -29,6 +28,7 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Response; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypeCreate; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @@ -39,7 +39,7 @@ public interface HawkbitDistributionSetTypesResource { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(JsonNode distributionSetTypes); + Response create(FirmwareDistributionSetTypeCreate[] distributionSetTypes); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java index 834cba8..d05a35b 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; import jakarta.ws.rs.Consumes; @@ -29,6 +28,8 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Response; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetAssignment; +import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetCreate; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @@ -39,7 +40,7 @@ public interface HawkbitDistributionSetsResource { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(JsonNode distributionSets); + Response create(FirmwareDistributionSetCreate[] distributionSets); @POST @Path("{id}/assignedTargets") @@ -47,7 +48,7 @@ public interface HawkbitDistributionSetsResource { @Produces(APPLICATION_HAL_JSON) Response assignTargets(@PathParam("id") Long id, @QueryParam("offline") Boolean offline, - JsonNode targets); + FirmwareDistributionSetAssignment[] targets); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitMediaType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitMediaType.java index 64b5236..5d89225 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitMediaType.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitMediaType.java @@ -1,5 +1,5 @@ /* - * Copyright 2026, OpenRemote Inc. + * Copyright 2025, OpenRemote Inc. * * See the CONTRIBUTORS.txt file in the distribution for a * full listing of individual contributors. diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java index 906b6dd..9d529a0 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -29,6 +28,7 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Response; +import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutCreate; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @@ -50,7 +50,7 @@ Response getRollouts(@QueryParam("offset") Integer offset, @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(JsonNode rollout); + Response create(FirmwareRolloutCreate rollout); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java index 6b0fab7..1d6802e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -29,6 +28,7 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Response; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypeCreate; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @@ -39,7 +39,7 @@ public interface HawkbitSoftwareModuleTypesResource { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(JsonNode softwareModuleTypes); + Response create(FirmwareSoftwareModuleTypeCreate[] softwareModuleTypes); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java index afb9142..1a13948 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; import jakarta.ws.rs.Consumes; @@ -29,8 +28,11 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Response; +import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; +import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleCreate; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.MediaType.MULTIPART_FORM_DATA; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("softwaremodules") @@ -39,7 +41,7 @@ public interface HawkbitSoftwareModulesResource { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(JsonNode softwareModules); + Response create(FirmwareSoftwareModuleCreate[] softwareModules); @GET @Produces(APPLICATION_JSON) @@ -56,6 +58,14 @@ Response getSoftwareModules(@QueryParam("offset") Integer offset, @Produces(APPLICATION_JSON) Response getArtifacts(@PathParam("id") Long id); + @POST + @Path("{id}/artifacts") + @Consumes(MULTIPART_FORM_DATA) + @Produces(APPLICATION_HAL_JSON) + Response uploadArtifact(@PathParam("id") Long id, + @QueryParam("filename") String filename, + MultipartFormDataOutput form); + @DELETE @Path("{id}") void delete(@PathParam("id") Long id); diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java index 3c5c252..bf0bbda 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -29,6 +28,8 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Response; +import org.openremote.extension.hawkbit.model.firmware.FirmwareAutoAssignDS; +import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterCreate; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @@ -49,7 +50,7 @@ Response getTargetFilters(@QueryParam("offset") Integer offset, @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(JsonNode filter); + Response create(FirmwareTargetFilterCreate filter); @DELETE @Path("{filterId}") @@ -65,7 +66,7 @@ Response getTargetFilters(@QueryParam("offset") Integer offset, @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) Response setAutoAssignDS(@PathParam("filterId") Long filterId, - JsonNode request); + FirmwareAutoAssignDS request); @DELETE @Path("{filterId}/autoAssignDS") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignDS.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignDS.java new file mode 100644 index 0000000..dbd052e --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignDS.java @@ -0,0 +1,30 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record FirmwareAutoAssignDS( + Long id, + String type, + Integer weight, + Boolean confirmationRequired) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java new file mode 100644 index 0000000..f084aa3 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java @@ -0,0 +1,31 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record FirmwareDistributionSetAssignment( + String id, + String type, + Long forcetime, + Integer weight, + Boolean confirmationRequired) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetCreate.java new file mode 100644 index 0000000..d5e4440 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetCreate.java @@ -0,0 +1,31 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record FirmwareDistributionSetCreate( + String name, + String version, + String type, + String description, + FirmwareModuleReference[] modules) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java index 7ffbd7f..78b6168 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.model.firmware; -import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -47,7 +46,7 @@ public interface FirmwareDistributionSetResource { @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createDistributionSet(@BeanParam RequestParams requestParams, - JsonNode distributionSet); + FirmwareDistributionSetCreate distributionSet); @POST @Path("{id}/assign") @@ -57,7 +56,7 @@ Response createDistributionSet(@BeanParam RequestParams requestParams, Response assignDistributionSet(@BeanParam RequestParams requestParams, @PathParam("id") Long id, @QueryParam("offline") Boolean offline, - JsonNode targets); + FirmwareDistributionSetAssignment[] targets); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeCreate.java new file mode 100644 index 0000000..f78cfc4 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeCreate.java @@ -0,0 +1,31 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record FirmwareDistributionSetTypeCreate( + String name, + String key, + String description, + FirmwareModuleReference[] mandatorymodules, + FirmwareModuleReference[] optionalmodules) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java index f3c375a..4716009 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.model.firmware; -import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -47,7 +46,7 @@ public interface FirmwareDistributionSetTypeResource { @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createDistributionSetType(@BeanParam RequestParams requestParams, - JsonNode distributionSetType); + FirmwareDistributionSetTypeCreate distributionSetType); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModuleReference.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModuleReference.java new file mode 100644 index 0000000..3eadb6f --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModuleReference.java @@ -0,0 +1,26 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record FirmwareModuleReference(Long id) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java new file mode 100644 index 0000000..022905f --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java @@ -0,0 +1,26 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record FirmwareRolloutAction(String action, String expression) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java new file mode 100644 index 0000000..9245c47 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java @@ -0,0 +1,26 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record FirmwareRolloutCondition(String condition, String expression) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCreate.java new file mode 100644 index 0000000..65a655d --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCreate.java @@ -0,0 +1,40 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record FirmwareRolloutCreate( + String name, + String description, + String targetFilterQuery, + Long distributionSetId, + Integer amountGroups, + Long forcetime, + Long startAt, + Integer weight, + String type, + FirmwareRolloutCondition successCondition, + FirmwareRolloutAction successAction, + FirmwareRolloutCondition errorCondition, + FirmwareRolloutAction errorAction, + Boolean confirmationRequired) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java index d6d3ced..c76aaed 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.model.firmware; -import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -61,7 +60,7 @@ Response getRollout(@BeanParam RequestParams requestParams, @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createRollout(@BeanParam RequestParams requestParams, - JsonNode rollout); + FirmwareRolloutCreate rollout); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleCreate.java new file mode 100644 index 0000000..5591f41 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleCreate.java @@ -0,0 +1,32 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record FirmwareSoftwareModuleCreate( + String name, + String version, + String type, + String description, + String vendor, + Boolean encrypted) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java index 683500d..fa14fbb 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.model.firmware; -import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -51,7 +50,7 @@ public interface FirmwareSoftwareModuleResource { @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createSoftwareModule(@BeanParam RequestParams requestParams, - JsonNode softwareModule); + FirmwareSoftwareModuleCreate softwareModule); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeCreate.java new file mode 100644 index 0000000..e7a8318 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeCreate.java @@ -0,0 +1,30 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record FirmwareSoftwareModuleTypeCreate( + String name, + String key, + String description, + Integer maxAssignments) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java index b69dfc2..6fd3293 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.model.firmware; -import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -47,7 +46,7 @@ public interface FirmwareSoftwareModuleTypeResource { @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createSoftwareModuleType(@BeanParam RequestParams requestParams, - JsonNode softwareModuleType); + FirmwareSoftwareModuleTypeCreate softwareModuleType); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterCreate.java new file mode 100644 index 0000000..2324e76 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterCreate.java @@ -0,0 +1,26 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.firmware; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record FirmwareTargetFilterCreate(String name, String query) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java index 9d6169c..8afdca5 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java @@ -19,7 +19,6 @@ */ package org.openremote.extension.hawkbit.model.firmware; -import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.BeanParam; @@ -61,7 +60,7 @@ Response getTargetFilter(@BeanParam RequestParams requestParams, @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createTargetFilter(@BeanParam RequestParams requestParams, - JsonNode filter); + FirmwareTargetFilterCreate filter); @DELETE @Path("{id}") @@ -83,7 +82,7 @@ Response getAutoAssignDS(@BeanParam RequestParams requestParams, @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response setAutoAssignDS(@BeanParam RequestParams requestParams, @PathParam("id") Long id, - JsonNode request); + FirmwareAutoAssignDS request); @DELETE @Path("{id}/autoAssignDS") From c7a412ae3bec19bec04241db162690ec64741ff6 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Fri, 15 May 2026 12:14:10 +0200 Subject: [PATCH 09/18] Restructuring, minor refactor on the response handling/proxying + added groovy tests. --- ...rvice.java => HawkbitFirmwareService.java} | 279 +++++++++++------- .../manager/HawkbitResponseHandler.java | 225 ++++++++++++++ .../FirmwareDistributionSetResourceImpl.java | 79 ----- ...irmwareSoftwareModuleTypeResourceImpl.java | 67 ----- .../FirmwareTargetFilterResourceImpl.java | 88 ------ .../manager/firmware/HawkbitResponse.java | 224 -------------- ...=> HawkbitDistributionSetTypesClient.java} | 17 +- ...ava => HawkbitDistributionSetsClient.java} | 21 +- ...source.java => HawkbitRolloutsClient.java} | 19 +- ... => HawkbitSoftwareModuleTypesClient.java} | 17 +- ...java => HawkbitSoftwareModulesClient.java} | 17 +- ...e.java => HawkbitTargetFiltersClient.java} | 23 +- ...esource.java => HawkbitTargetsClient.java} | 27 +- .../resource/DistributionSetResourceImpl.java | 81 +++++ .../DistributionSetTypeResourceImpl.java} | 50 ++-- .../RolloutResourceImpl.java} | 54 ++-- .../SoftwareModuleResourceImpl.java} | 46 +-- .../SoftwareModuleTypeResourceImpl.java | 69 +++++ .../resource/TargetFilterResourceImpl.java | 90 ++++++ .../TargetResourceImpl.java} | 48 +-- .../{firmware => }/FirmwareMetaItemType.java | 9 +- .../{firmware => }/FirmwareModelProvider.java | 2 +- .../AutoAssignDistributionSetRequest.java} | 4 +- .../DistributionSetAssignmentRequest.java} | 4 +- .../DistributionSetCreateRequest.java} | 6 +- .../DistributionSetTypeCreateRequest.java} | 8 +- .../MetadataUpdateRequest.java} | 4 +- .../RolloutActionRequest.java} | 4 +- .../hawkbit/RolloutConditionRequest.java | 26 ++ .../RolloutCreateRequest.java} | 12 +- .../SoftwareModuleCreateRequest.java} | 4 +- .../SoftwareModuleReferenceRequest.java} | 4 +- .../SoftwareModuleTypeCreateRequest.java} | 4 +- .../Target.java} | 8 +- .../TargetCreateRequest.java} | 4 +- .../TargetFilterCreateRequest.java} | 4 +- .../DistributionSetResource.java} | 21 +- .../DistributionSetTypeResource.java} | 18 +- .../RolloutResource.java} | 20 +- .../SoftwareModuleResource.java} | 18 +- .../SoftwareModuleTypeResource.java} | 18 +- .../TargetFilterResource.java} | 25 +- .../TargetResource.java} | 15 +- .../org.openremote.model.AssetModelProvider | 2 +- .../org.openremote.model.ContainerService | 2 +- .../manager/HawkbitFirmwareServiceTest.groovy | 215 ++++++++++++++ .../manager/HawkbitResponseHandlerTest.groovy | 232 +++++++++++++++ 47 files changed, 1340 insertions(+), 894 deletions(-) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/{firmware/FirmwareService.java => HawkbitFirmwareService.java} (71%) create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseHandler.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/{HawkbitDistributionSetTypesResource.java => HawkbitDistributionSetTypesClient.java} (80%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/{HawkbitDistributionSetsResource.java => HawkbitDistributionSetsClient.java} (72%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/{HawkbitRolloutsResource.java => HawkbitRolloutsClient.java} (82%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/{HawkbitSoftwareModuleTypesResource.java => HawkbitSoftwareModuleTypesClient.java} (75%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/{HawkbitSoftwareModulesResource.java => HawkbitSoftwareModulesClient.java} (81%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/{HawkbitTargetFiltersResource.java => HawkbitTargetFiltersClient.java} (73%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/{HawkbitTargetsResource.java => HawkbitTargetsClient.java} (74%) create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/{firmware/FirmwareDistributionSetTypeResourceImpl.java => resource/DistributionSetTypeResourceImpl.java} (50%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/{firmware/FirmwareRolloutResourceImpl.java => resource/RolloutResourceImpl.java} (50%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/{firmware/FirmwareSoftwareModuleResourceImpl.java => resource/SoftwareModuleResourceImpl.java} (59%) create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java rename hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/{firmware/FirmwareTargetResourceImpl.java => resource/TargetResourceImpl.java} (52%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware => }/FirmwareMetaItemType.java (97%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware => }/FirmwareModelProvider.java (96%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareAutoAssignDS.java => hawkbit/AutoAssignDistributionSetRequest.java} (90%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareDistributionSetAssignment.java => hawkbit/DistributionSetAssignmentRequest.java} (90%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareDistributionSetCreate.java => hawkbit/DistributionSetCreateRequest.java} (87%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareDistributionSetTypeCreate.java => hawkbit/DistributionSetTypeCreateRequest.java} (81%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareModuleReference.java => hawkbit/MetadataUpdateRequest.java} (89%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareTargetFilterCreate.java => hawkbit/RolloutActionRequest.java} (87%) create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutConditionRequest.java rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareRolloutCreate.java => hawkbit/RolloutCreateRequest.java} (80%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareSoftwareModuleCreate.java => hawkbit/SoftwareModuleCreateRequest.java} (91%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareMetadataUpdate.java => hawkbit/SoftwareModuleReferenceRequest.java} (89%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareSoftwareModuleTypeCreate.java => hawkbit/SoftwareModuleTypeCreateRequest.java} (90%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareTarget.java => hawkbit/Target.java} (82%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareRolloutCondition.java => hawkbit/TargetCreateRequest.java} (86%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareRolloutAction.java => hawkbit/TargetFilterCreateRequest.java} (87%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareDistributionSetResource.java => resource/DistributionSetResource.java} (82%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareDistributionSetTypeResource.java => resource/DistributionSetTypeResource.java} (86%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareRolloutResource.java => resource/RolloutResource.java} (86%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareSoftwareModuleResource.java => resource/SoftwareModuleResource.java} (86%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareSoftwareModuleTypeResource.java => resource/SoftwareModuleTypeResource.java} (82%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareTargetFilterResource.java => resource/TargetFilterResource.java} (81%) rename hawkbit/src/main/java/org/openremote/extension/hawkbit/model/{firmware/FirmwareTargetResource.java => resource/TargetResource.java} (91%) create mode 100644 hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy create mode 100644 hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitResponseHandlerTest.groovy diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java similarity index 71% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java index b012d48..2822445 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java @@ -17,21 +17,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.manager.firmware; - -import static org.openremote.container.web.WebTargetBuilder.CONNECTION_POOL_SIZE; -import static org.openremote.container.web.WebTargetBuilder.CONNECTION_TIMEOUT_MILLISECONDS; -import static org.openremote.container.web.WebTargetBuilder.createClient; -import static org.openremote.model.syslog.SyslogCategory.API; -import static org.openremote.model.util.MapAccess.getString; - -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.*; -import java.util.concurrent.ExecutorService; -import java.util.logging.Level; -import java.util.logging.Logger; +package org.openremote.extension.hawkbit.manager; import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.WebApplicationException; @@ -41,24 +27,21 @@ import jakarta.ws.rs.core.Response; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; -import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; import org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataWriter; import org.openremote.container.timer.TimerService; import org.openremote.container.web.WebClient; import org.openremote.container.web.WebTargetBuilder; +import org.openremote.extension.hawkbit.manager.hawkbit.*; +import org.openremote.extension.hawkbit.manager.resource.*; +import org.openremote.extension.hawkbit.model.FirmwareMetaItemType; +import org.openremote.extension.hawkbit.model.hawkbit.MetadataUpdateRequest; +import org.openremote.extension.hawkbit.model.hawkbit.Target; +import org.openremote.extension.hawkbit.model.hawkbit.TargetCreateRequest; import org.openremote.manager.asset.AssetProcessingService; import org.openremote.manager.event.ClientEventService; import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitBasicAuth; -import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitDistributionSetsResource; -import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitDistributionSetTypesResource; -import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitRolloutsResource; -import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitSoftwareModulesResource; -import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitSoftwareModuleTypesResource; -import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitTargetFiltersResource; -import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitTargetsResource; import org.openremote.manager.web.ManagerWebService; import org.openremote.model.Container; import org.openremote.model.ContainerService; @@ -68,15 +51,24 @@ import org.openremote.model.attribute.Attribute; import org.openremote.model.attribute.AttributeEvent; import org.openremote.model.attribute.MetaMap; -import org.openremote.extension.hawkbit.model.firmware.FirmwareMetaItemType; -import org.openremote.extension.hawkbit.model.firmware.FirmwareMetadataUpdate; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTarget; import org.openremote.model.syslog.SyslogCategory; import org.openremote.model.util.TextUtil; import org.openremote.model.util.ValueUtil; import org.openremote.model.value.AttributeDescriptor; -public class FirmwareService implements ContainerService { +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.openremote.container.web.WebTargetBuilder.*; +import static org.openremote.model.syslog.SyslogCategory.API; +import static org.openremote.model.util.MapAccess.getString; + +public class HawkbitFirmwareService implements ContainerService { public static final String HAWKBIT_REALM = "HAWKBIT_REALM"; @@ -89,7 +81,7 @@ public class FirmwareService implements ContainerService { public static final String HAWKBIT_MANAGEMENT_API_URL = "HAWKBIT_MANAGEMENT_API_URL"; public static final String HAWKBIT_MANAGEMENT_API_URL_DEFAULT = "http://localhost:8083/hawkbit/rest/v1"; - private static final Logger LOG = SyslogCategory.getLogger(API, FirmwareService.class); + private static final Logger LOG = SyslogCategory.getLogger(API, HawkbitFirmwareService.class); protected ResteasyClient client; @@ -99,13 +91,14 @@ public class FirmwareService implements ContainerService { protected AssetProcessingService assetProcessingService; protected ExecutorService executorService; protected TimerService timerService; - protected HawkbitTargetsResource targetsResource; - protected HawkbitDistributionSetsResource distributionSetsResource; - protected HawkbitDistributionSetTypesResource distributionSetTypesResource; - protected HawkbitSoftwareModulesResource softwareModulesResource; - protected HawkbitSoftwareModuleTypesResource softwareModuleTypesResource; - protected HawkbitRolloutsResource rolloutsResource; - protected HawkbitTargetFiltersResource targetFiltersResource; + + protected HawkbitTargetsClient targets; + protected HawkbitDistributionSetsClient distributionSets; + protected HawkbitDistributionSetTypesClient distributionSetTypes; + protected HawkbitSoftwareModulesClient softwareModules; + protected HawkbitSoftwareModuleTypesClient softwareModuleTypes; + protected HawkbitRolloutsClient rollouts; + protected HawkbitTargetFiltersClient targetFilters; @Override public void init(Container container) throws Exception { @@ -115,23 +108,25 @@ public void init(Container container) throws Exception { timerService = container.getService(TimerService.class); identityService = container.getService(ManagerIdentityService.class); - // API resources container.getService(ManagerWebService.class).addApiSingleton( - new FirmwareTargetResourceImpl(timerService, identityService, this)); + new TargetResourceImpl(timerService, identityService, this)); container.getService(ManagerWebService.class).addApiSingleton( - new FirmwareDistributionSetResourceImpl(timerService, identityService, this)); + new DistributionSetResourceImpl(timerService, identityService, this)); container.getService(ManagerWebService.class).addApiSingleton( - new FirmwareDistributionSetTypeResourceImpl(timerService, identityService, this)); + new DistributionSetTypeResourceImpl(timerService, identityService, this)); container.getService(ManagerWebService.class).addApiSingleton( - new FirmwareSoftwareModuleResourceImpl(timerService, identityService, this)); + new SoftwareModuleResourceImpl(timerService, identityService, this)); container.getService(ManagerWebService.class).addApiSingleton( - new FirmwareSoftwareModuleTypeResourceImpl(timerService, identityService, this)); + new SoftwareModuleTypeResourceImpl(timerService, identityService, this)); container.getService(ManagerWebService.class).addApiSingleton( - new FirmwareRolloutResourceImpl(timerService, identityService, this)); + new RolloutResourceImpl(timerService, identityService, this)); container.getService(ManagerWebService.class).addApiSingleton( - new FirmwareTargetFilterResourceImpl(timerService, identityService, this)); + new TargetFilterResourceImpl(timerService, identityService, this)); } + /** + * Builds the hawkBit REST client and subscribes to asset/attribute events. + */ @Override public void start(Container container) throws Exception { String hawkbitURI = getString(container.getConfig(), HAWKBIT_MANAGEMENT_API_URL, @@ -164,7 +159,7 @@ public void start(Container container) throws Exception { client = createClient(org.openremote.container.Container.EXECUTOR, CONNECTION_POOL_SIZE, CONNECTION_TIMEOUT_MILLISECONDS, resteasyClientBuilder -> { - WebClient.registerDefaults((ResteasyClientBuilderImpl) resteasyClientBuilder); + WebClient.registerDefaults(resteasyClientBuilder); ResteasyJackson2Provider provider = new ResteasyJackson2Provider(); provider.setMapper(ValueUtil.JSON); resteasyClientBuilder.register(provider); @@ -177,22 +172,19 @@ public void start(Container container) throws Exception { HttpHeaders.AUTHORIZATION, HawkbitBasicAuth.buildAuthorizationHeader(hawkbitUsername, hawkbitPassword))); - // Set targets resource - targetsResource = webTarget.proxy(HawkbitTargetsResource.class); - distributionSetsResource = webTarget.proxy(HawkbitDistributionSetsResource.class); - distributionSetTypesResource = webTarget.proxy(HawkbitDistributionSetTypesResource.class); - softwareModulesResource = webTarget.proxy(HawkbitSoftwareModulesResource.class); - softwareModuleTypesResource = webTarget.proxy(HawkbitSoftwareModuleTypesResource.class); - rolloutsResource = webTarget.proxy(HawkbitRolloutsResource.class); - targetFiltersResource = webTarget.proxy(HawkbitTargetFiltersResource.class); + targets = webTarget.proxy(HawkbitTargetsClient.class); + distributionSets = webTarget.proxy(HawkbitDistributionSetsClient.class); + distributionSetTypes = webTarget.proxy(HawkbitDistributionSetTypesClient.class); + softwareModules = webTarget.proxy(HawkbitSoftwareModulesClient.class); + softwareModuleTypes = webTarget.proxy(HawkbitSoftwareModuleTypesClient.class); + rollouts = webTarget.proxy(HawkbitRolloutsClient.class); + targetFilters = webTarget.proxy(HawkbitTargetFiltersClient.class); - // Subscribe on asset events clientEventService.addSubscription( AssetEvent.class, null, this::onAssetChange); - // Subscribe on attribute events clientEventService.addSubscription( AttributeEvent.class, null, @@ -204,42 +196,26 @@ public void start(Container container) throws Exception { @Override public void stop(Container container) throws Exception { - - } - - public Response uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream inputStream, - String originalFilename, String filename) { - String effectiveFilename = TextUtil.isNullOrEmpty(filename) ? originalFilename : filename; - String uploadFilename = TextUtil.isNullOrEmpty(effectiveFilename) ? "artifact.bin" : effectiveFilename; - MultipartFormDataOutput form = new MultipartFormDataOutput(); - form.addFormData("file", inputStream, MediaType.APPLICATION_OCTET_STREAM_TYPE, uploadFilename); - return HawkbitResponse.from(softwareModulesResource.uploadArtifact(softwareModuleId, - TextUtil.isNullOrEmpty(effectiveFilename) ? null : effectiveFilename, - form)) - .asResource(); + // Client lifecycle is managed by the container. } - private void onAssetChange(AssetEvent assetEvent) { - if (!Objects.equals(assetEvent.getRealm(), hawkbitRealm)) - { + protected void onAssetChange(AssetEvent assetEvent) { + if (!Objects.equals(assetEvent.getRealm(), hawkbitRealm)) { return; } - // Submit the assetEvent to the executorService executorService.submit(() -> handleAssetChange(assetEvent)); } - private void onAttributeChange(AttributeEvent attributeEvent) { - if (!Objects.equals(attributeEvent.getRealm(), hawkbitRealm)) - { + protected void onAttributeChange(AttributeEvent attributeEvent) { + if (!Objects.equals(attributeEvent.getRealm(), hawkbitRealm)) { return; } - // Submit the attributeEvent to the executorService executorService.submit(() -> handleAttributeChange(attributeEvent)); } - private void handleAttributeChange(AttributeEvent attributeEvent) { + protected void handleAttributeChange(AttributeEvent attributeEvent) { if (!hasFirmwareMetadata(attributeEvent.getAssetType(), attributeEvent.getName(), attributeEvent.getMeta())) { return; } @@ -255,7 +231,11 @@ private void handleAttributeChange(AttributeEvent attributeEvent) { attributeEvent.getValue().orElse(null)); } - private void handleAssetChange(AssetEvent assetEvent) { + /** + * Synchronises an OpenRemote asset with a hawkBit target. + * CREATE ensures the target exists; UPDATE recreates it if missing; DELETE removes it. + */ + protected void handleAssetChange(AssetEvent assetEvent) { Asset asset = assetEvent.getAsset(); if (getFirmwareTargetInfoDescriptor(asset).isEmpty()) { @@ -265,7 +245,7 @@ private void handleAssetChange(AssetEvent assetEvent) { String controllerId = asset.getId(); boolean shouldUpdateFirmwareTargetInfo = false; - LOG.info("Processing hawkbit target sync cause=" + assetEvent.getCause() + LOG.fine("Processing hawkbit target sync cause=" + assetEvent.getCause() + ", assetId=" + asset.getId() + ", assetType=" + asset.getType() + ", controllerId=" + controllerId); @@ -276,7 +256,7 @@ private void handleAssetChange(AssetEvent assetEvent) { break; case UPDATE: LOG.fine("Checking hawkbit target for update asset id=" + asset.getId()); - FirmwareTarget existingTarget; + Target existingTarget; try { existingTarget = getFirmwareTarget(controllerId); } catch (Exception e) { @@ -309,7 +289,7 @@ private void handleAssetChange(AssetEvent assetEvent) { } } - private void updateFirmwareTargetMetadata(Asset asset) { + protected void updateFirmwareTargetMetadata(Asset asset) { String controllerId = asset.getId(); for (Attribute attribute : asset.getAttributes().values()) { if (!hasFirmwareMetadata(asset.getType(), attribute.getName(), attribute.getMeta())) { @@ -320,7 +300,11 @@ private void updateFirmwareTargetMetadata(Asset asset) { } } - private boolean hasFirmwareMetadata(String assetType, String attributeName, MetaMap meta) { + /** + * Checks whether an attribute (by instance meta or type descriptor meta) is marked + * as firmware metadata. + */ + protected boolean hasFirmwareMetadata(String assetType, String attributeName, MetaMap meta) { if (hasFirmwareMetadata(meta)) { return true; } @@ -337,14 +321,14 @@ private boolean hasFirmwareMetadata(String assetType, String attributeName, Meta .orElse(false); } - private boolean hasFirmwareMetadata(MetaMap meta) { + protected boolean hasFirmwareMetadata(MetaMap meta) { return meta != null && meta.get(FirmwareMetaItemType.FIRMWARE_METADATA) - .flatMap(metaItem -> metaItem.getValue(Boolean.class)) - .orElse(false); + .flatMap(metaItem -> metaItem.getValue(Boolean.class)) + .orElse(false); } - private void syncFirmwareTargetMetadataValue(String controllerId, String key, Object value) { + protected void syncFirmwareTargetMetadataValue(String controllerId, String key, Object value) { if (isAttributeEmptyOrNull(value)) { deleteFirmwareTargetMetadata(controllerId, key); return; @@ -360,15 +344,14 @@ private void syncFirmwareTargetMetadataValue(String controllerId, String key, Ob updateFirmwareTargetMetadata(controllerId, key, metadataValue.get()); } - private boolean isAttributeEmptyOrNull(Object value) { + protected boolean isAttributeEmptyOrNull(Object value) { return value == null || ValueUtil.getStringCoerced(value) .map(String::isEmpty) .orElse(false); } - private void updateFirmwareTargetMetadata(String controllerId, String key, String value) { - try { - targetsResource.updateMetadata(controllerId, key, new FirmwareMetadataUpdate(value)); + protected void updateFirmwareTargetMetadata(String controllerId, String key, String value) { + try (Response response = targets.updateMetadata(controllerId, key, new MetadataUpdateRequest(value))) { LOG.fine("Updated hawkbit target metadata targetId=" + controllerId + ", key=" + key); } catch (NotFoundException e) { LOG.fine("hawkbit target not found for metadata sync targetId=" @@ -379,9 +362,8 @@ private void updateFirmwareTargetMetadata(String controllerId, String key, Strin } } - private void deleteFirmwareTargetMetadata(String controllerId, String key) { - try { - targetsResource.deleteMetadata(controllerId, key); + protected void deleteFirmwareTargetMetadata(String controllerId, String key) { + try (Response response = targets.deleteMetadata(controllerId, key)) { LOG.fine("Deleted hawkbit target metadata targetId=" + controllerId + ", key=" + key); } catch (NotFoundException e) { LOG.fine("hawkbit target metadata not found for delete targetId=" @@ -392,7 +374,11 @@ private void deleteFirmwareTargetMetadata(String controllerId, String key) { } } - private Optional> getFirmwareTargetInfoDescriptor(Asset asset) { + /** + * Finds the single attribute descriptor marked as {@code firmwareTarget} for the given asset type. + * Returns empty if none or more than one is found. + */ + protected Optional> getFirmwareTargetInfoDescriptor(Asset asset) { // TODO: Decide whether firmwareTarget should also be honored when defined on // an asset attribute instance instead of only on the asset type descriptor. Optional assetTypeInfo = ValueUtil.getAssetInfo(asset.getType()); @@ -405,9 +391,9 @@ private Optional> getFirmwareTargetInfoDescriptor(Asset attributeDescriptor.getMeta() != null && attributeDescriptor.getMeta() - .get(FirmwareMetaItemType.FIRMWARE_TARGET) - .flatMap(metaItem -> metaItem.getValue(Boolean.class)) - .orElse(false)) + .get(FirmwareMetaItemType.FIRMWARE_TARGET) + .flatMap(metaItem -> metaItem.getValue(Boolean.class)) + .orElse(false)) .toList(); if (matchingDescriptors.isEmpty()) { @@ -424,16 +410,16 @@ private Optional> getFirmwareTargetInfoDescriptor(Asset asset) { + protected TargetCreateRequest buildFirmwareTarget(Asset asset) { String controllerId = asset.getId(); - String targetName = asset.getAssetType() + "-" + controllerId; - String targetDescription = "assetId=" + asset.getId() + "; realm=" + asset.getRealm(); - return new FirmwareTarget(controllerId, targetName, targetDescription); + String targetName = asset.getAssetType() + "-" + controllerId; + String targetDescription = "assetId=" + asset.getId() + "; realm=" + asset.getRealm(); + return new TargetCreateRequest(controllerId, targetName, targetDescription); } - private boolean createFirmwareTarget(FirmwareTarget target) { + protected boolean createFirmwareTarget(TargetCreateRequest target) { LOG.info("Creating hawkbit target id=" + target.controllerId()); - try (Response response = targetsResource.create(new FirmwareTarget[] { target })) { + try (Response response = targets.create(new TargetCreateRequest[]{target})) { boolean created = response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL; if (!created) { LOG.warning("Failed to create hawkbit target id=" + target.controllerId() @@ -446,16 +432,19 @@ private boolean createFirmwareTarget(FirmwareTarget target) { } } - private void deleteFirmwareTarget(String controllerId) { - try { - targetsResource.delete(controllerId); + protected void deleteFirmwareTarget(String controllerId) { + try (Response response = targets.delete(controllerId)) { LOG.info("Deleted hawkbit target id=" + controllerId); } catch (Exception e) { LOG.log(Level.WARNING, "Failed to delete hawkbit target id=" + controllerId, e); } } - private void updateFirmwareTargetInfo(AssetEvent assetEvent) { + /** + * Builds a JSON value containing the hawkBit target's controllerId and securityToken, + * then sends it as an attribute event if the value has changed. + */ + protected void updateFirmwareTargetInfo(AssetEvent assetEvent) { Asset asset = assetEvent.getAsset(); Optional> firmwareTargetInfoDescriptor = getFirmwareTargetInfoDescriptor(asset); if (firmwareTargetInfoDescriptor.isEmpty()) { @@ -469,7 +458,7 @@ private void updateFirmwareTargetInfo(AssetEvent assetEvent) { case CREATE: case UPDATE: try { - FirmwareTarget firmwareTarget = getFirmwareTarget(controllerId); + Target firmwareTarget = getFirmwareTarget(controllerId); if (firmwareTarget == null) { return; } @@ -500,8 +489,12 @@ private void updateFirmwareTargetInfo(AssetEvent assetEvent) { } } - private FirmwareTarget getFirmwareTarget(String controllerId) { - try (Response response = targetsResource.get(controllerId)) { + /** + * Queries hawkBit for a target by controllerId. + * Returns {@code null} if the target is not found (404). + */ + protected Target getFirmwareTarget(String controllerId) { + try (Response response = targets.get(controllerId)) { if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { return null; } @@ -509,8 +502,72 @@ private FirmwareTarget getFirmwareTarget(String controllerId) { throw new WebApplicationException("hawkBit target request failed with status " + response.getStatus(), response.getStatus()); } - return response.readEntity(FirmwareTarget.class); + return response.readEntity(Target.class); } } + /** + * Uploads an artifact file to the given hawkBit software module. + */ + public Response uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream inputStream, + String originalFilename, String filename) { + String effectiveFilename = TextUtil.isNullOrEmpty(filename) ? originalFilename : filename; + String uploadFilename = TextUtil.isNullOrEmpty(effectiveFilename) ? "artifact.bin" : effectiveFilename; + MultipartFormDataOutput form = new MultipartFormDataOutput(); + form.addFormData("file", inputStream, MediaType.APPLICATION_OCTET_STREAM_TYPE, uploadFilename); + return HawkbitResponseHandler.call("Failed to upload artifact for firmware software module '" + softwareModuleId + "'", + () -> softwareModules.uploadArtifact(softwareModuleId, + TextUtil.isNullOrEmpty(effectiveFilename) ? null : effectiveFilename, + form)); + } + + /** + * Returns the hawkBit targets client. + */ + public HawkbitTargetsClient targets() { + return targets; + } + + /** + * Returns the hawkBit distribution sets client. + */ + public HawkbitDistributionSetsClient distributionSets() { + return distributionSets; + } + + /** + * Returns the hawkBit distribution set types client. + */ + public HawkbitDistributionSetTypesClient distributionSetTypes() { + return distributionSetTypes; + } + + /** + * Returns the hawkBit software modules client. + */ + public HawkbitSoftwareModulesClient softwareModules() { + return softwareModules; + } + + /** + * Returns the hawkBit software module types client. + */ + public HawkbitSoftwareModuleTypesClient softwareModuleTypes() { + return softwareModuleTypes; + } + + /** + * Returns the hawkBit rollouts client. + */ + public HawkbitRolloutsClient rollouts() { + return rollouts; + } + + /** + * Returns the hawkBit target filters client. + */ + public HawkbitTargetFiltersClient targetFilters() { + return targetFilters; + } + } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseHandler.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseHandler.java new file mode 100644 index 0000000..e75b7ad --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseHandler.java @@ -0,0 +1,225 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.manager; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.openremote.model.util.ValueUtil; + +import java.util.Map; + +public final class HawkbitResponseHandler { + + private static final Map HAL_LINK_FIELDS = Map.of( + "distributionset", new LinkFieldMapping("distributionSetId", "distributionSetName")); + + private HawkbitResponseHandler() { + } + + /** + * Executes a hawkBit call, adapts the response (strips HAL, flattens collections), + * and wraps any unexpected failure as {@code BAD_GATEWAY}. + *

+ * The upstream {@link Response} is consumed and closed by this call. + */ + public static Response call(String errorMessage, HawkbitCall call) { + try { + return adaptHawkbitResponse(call.execute()); + } catch (WebApplicationException e) { + throw e; + } catch (Exception e) { + throw new WebApplicationException(errorMessage, e, Response.Status.BAD_GATEWAY); + } + } + + /** + * Consumes the upstream response and builds a new one with HAL fields removed. + * Preserves non-JSON bodies and empty responses unchanged. + */ + protected static Response adaptHawkbitResponse(Response response) { + try (response) { + Response.ResponseBuilder builder = Response.status(response.getStatus()); + if (!response.hasEntity()) { + return builder.build(); + } + + String body = response.readEntity(String.class); + if (body.isBlank()) { + return builder.build(); + } + + try { + JsonNode root = ValueUtil.JSON.readTree(body); + JsonNode formatted = isCollectionResponse(root) ? toFlatPage(root) : cleanHalFields(root); + return builder + .type(MediaType.APPLICATION_JSON_TYPE) + .entity(ValueUtil.JSON.writeValueAsString(formatted)) + .build(); + } catch (Exception ignored) { + MediaType mediaType = response.getMediaType() == null + ? MediaType.TEXT_PLAIN_TYPE + : response.getMediaType(); + return builder.type(mediaType).entity(body).build(); + } + } catch (Exception e) { + throw new WebApplicationException("Failed to adapt hawkBit response", e, + Response.Status.BAD_GATEWAY); + } + } + + /** + * Detects collection responses (arrays, paged objects, or HAL {@code _embedded} arrays). + * Single resources with {@code _embedded} relations are excluded by checking for + * typical identifier fields such as {@code id} or {@code controllerId}. + */ + protected static boolean isCollectionResponse(JsonNode root) { + if (root.isArray()) { + return true; + } + if (root.path("content").isArray()) { + return true; + } + JsonNode embedded = root.path("_embedded"); + if (embedded.isObject() && !firstArrayItems(embedded).isEmpty()) { + // Single HAL resources may contain _embedded relations; only treat as collection + // if the root lacks typical single-resource identifier fields. + return !root.has("id") && !root.has("controllerId"); + } + return false; + } + + protected static ObjectNode toFlatPage(JsonNode root) { + ArrayNode content = JsonNodeFactory.instance.arrayNode(); + if (root.isArray()) { + root.forEach(item -> content.add(cleanHalFields(item))); + } else if (root.has("_embedded")) { + firstArrayItems(root.get("_embedded")).forEach(item -> content.add(cleanHalFields(item))); + } else if (root.path("content").isArray()) { + root.get("content").forEach(item -> content.add(cleanHalFields(item))); + } + + ObjectNode formatted = JsonNodeFactory.instance.objectNode(); + formatted.set("content", content); + formatted.put("total", intFieldOrDefault(root, "total", + intFieldOrDefault(root.path("page"), "totalElements", content.size()))); + formatted.put("size", intFieldOrDefault(root, "size", + intFieldOrDefault(root.path("page"), "size", content.size()))); + return formatted; + } + + /** + * Recursively removes {@code _links} and {@code _embedded} from HAL JSON, + * copying any mapped links to explicit fields (e.g. {@code distributionSetId}). + */ + protected static JsonNode cleanHalFields(JsonNode node) { + return switch (node) { + case ArrayNode array -> { + ArrayNode formatted = JsonNodeFactory.instance.arrayNode(); + array.forEach(item -> formatted.add(cleanHalFields(item))); + yield formatted; + } + case ObjectNode object -> { + ObjectNode formatted = JsonNodeFactory.instance.objectNode(); + for (Map.Entry field : object.properties()) { + if ("_links".equals(field.getKey()) || "_embedded".equals(field.getKey())) { + continue; + } + formatted.set(field.getKey(), cleanHalFields(field.getValue())); + } + copyMappedHalLinkFields(object.path("_links"), formatted); + yield formatted; + } + default -> node; + }; + } + + protected static void copyMappedHalLinkFields(JsonNode links, ObjectNode target) { + if (!links.isObject()) { + return; + } + + HAL_LINK_FIELDS.forEach((rel, mapping) -> { + JsonNode link = links.path(rel); + Long id = extractIdFromHref(link.path("href")); + if (id != null && !target.has(mapping.idField())) { + target.put(mapping.idField(), id); + } + JsonNode name = link.path("name"); + if (name.isTextual() && !target.has(mapping.nameField())) { + target.put(mapping.nameField(), name.textValue()); + } + }); + } + + protected static Long extractIdFromHref(JsonNode hrefNode) { + if (!hrefNode.isTextual()) { + return null; + } + + String href = hrefNode.textValue(); + int end = href.endsWith("/") ? href.length() - 1 : href.length(); + int start = href.lastIndexOf('/', end - 1) + 1; + if (start >= end) { + return null; + } + try { + return Long.parseLong(href.substring(start, end)); + } catch (NumberFormatException ignored) { + return null; + } + } + + protected static ArrayNode firstArrayItems(JsonNode embedded) { + ArrayNode content = JsonNodeFactory.instance.arrayNode(); + if (!embedded.isObject()) { + return content; + } + + for (JsonNode value : embedded) { + if (value.isArray()) { + value.forEach(content::add); + return content; + } + } + return content; + } + + protected static int intFieldOrDefault(JsonNode node, String field, int defaultValue) { + JsonNode value = node.path(field); + return value.isNumber() ? value.intValue() : defaultValue; + } + + /** + * Replaces {@link java.util.function.Supplier} to allow checked exceptions + * to propagate without {@code UndeclaredThrowableException} wrapping. + */ + @FunctionalInterface + public interface HawkbitCall { + Response execute() throws Exception; + } + + protected record LinkFieldMapping(String idField, String nameField) { + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java deleted file mode 100644 index b6fed9c..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetResourceImpl.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.manager.firmware; - -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Response; -import org.openremote.container.timer.TimerService; -import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.manager.web.ManagerWebResource; -import org.openremote.model.http.RequestParams; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetAssignment; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetCreate; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetResource; - -public class FirmwareDistributionSetResourceImpl extends ManagerWebResource - implements FirmwareDistributionSetResource { - - protected final FirmwareService firmwareService; - - public FirmwareDistributionSetResourceImpl(TimerService timerService, ManagerIdentityService identityService, - FirmwareService firmwareService) { - super(timerService, identityService); - this.firmwareService = firmwareService; - } - - @Override - public Response createDistributionSet(RequestParams requestParams, - FirmwareDistributionSetCreate distributionSet) { - return HawkbitResponse.proxy("Failed to create firmware distribution set", - () -> firmwareService.distributionSetsResource.create( - new FirmwareDistributionSetCreate[] { distributionSet })).asResource(); - } - - @Override - public Response assignDistributionSet(RequestParams requestParams, Long id, - Boolean offline, - FirmwareDistributionSetAssignment[] targets) { - if (targets == null || targets.length == 0) { - throw new WebApplicationException("Assignment requires at least one target", Response.Status.BAD_REQUEST); - } - return HawkbitResponse.proxy("Failed to assign firmware distribution set '" + id + "'", - () -> firmwareService.distributionSetsResource.assignTargets(id, offline, targets)).asResource(); - } - - @Override - public Response getDistributionSets(RequestParams requestParams, Integer offset, Integer limit) { - return HawkbitResponse.proxy("Failed to retrieve firmware distribution sets", - () -> firmwareService.distributionSetsResource.getDistributionSets(offset, limit)).asPage(); - } - - @Override - public Response getDistributionSet(RequestParams requestParams, Long id) { - return HawkbitResponse.proxy("Failed to retrieve firmware distribution set '" + id + "'", - () -> firmwareService.distributionSetsResource.get(id)).asResource(); - } - - @Override - public void deleteDistributionSet(RequestParams requestParams, Long id) { - HawkbitResponse.proxy("Failed to delete firmware distribution set '" + id + "'", - () -> firmwareService.distributionSetsResource.delete(id)); - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java deleted file mode 100644 index 310b0de..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleTypeResourceImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.manager.firmware; - -import jakarta.ws.rs.core.Response; -import org.openremote.container.timer.TimerService; -import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.manager.web.ManagerWebResource; -import org.openremote.model.http.RequestParams; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypeCreate; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypeResource; - -public class FirmwareSoftwareModuleTypeResourceImpl extends ManagerWebResource - implements FirmwareSoftwareModuleTypeResource { - - protected final FirmwareService firmwareService; - - public FirmwareSoftwareModuleTypeResourceImpl(TimerService timerService, ManagerIdentityService identityService, - FirmwareService firmwareService) { - super(timerService, identityService); - this.firmwareService = firmwareService; - } - - @Override - public Response createSoftwareModuleType(RequestParams requestParams, - FirmwareSoftwareModuleTypeCreate softwareModuleType) { - return HawkbitResponse.proxy("Failed to create firmware software module type", - () -> firmwareService.softwareModuleTypesResource.create( - new FirmwareSoftwareModuleTypeCreate[] { softwareModuleType })).asResource(); - } - - @Override - public Response getSoftwareModuleTypes(RequestParams requestParams, Integer offset, - Integer limit) { - return HawkbitResponse.proxy("Failed to retrieve firmware software module types", - () -> firmwareService.softwareModuleTypesResource.getSoftwareModuleTypes(offset, limit)).asPage(); - } - - @Override - public Response getSoftwareModuleType(RequestParams requestParams, Long id) { - return HawkbitResponse.proxy("Failed to retrieve firmware software module type '" + id + "'", - () -> firmwareService.softwareModuleTypesResource.get(id)).asResource(); - } - - @Override - public void deleteSoftwareModuleType(RequestParams requestParams, Long id) { - HawkbitResponse.proxy("Failed to delete firmware software module type '" + id + "'", - () -> firmwareService.softwareModuleTypesResource.delete(id)); - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java deleted file mode 100644 index e216937..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetFilterResourceImpl.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.manager.firmware; - -import jakarta.ws.rs.core.Response; -import org.openremote.container.timer.TimerService; -import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.manager.web.ManagerWebResource; -import org.openremote.extension.hawkbit.model.firmware.FirmwareAutoAssignDS; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterCreate; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterResource; -import org.openremote.model.http.RequestParams; - -public class FirmwareTargetFilterResourceImpl extends ManagerWebResource - implements FirmwareTargetFilterResource { - - protected final FirmwareService firmwareService; - - public FirmwareTargetFilterResourceImpl(TimerService timerService, ManagerIdentityService identityService, - FirmwareService firmwareService) { - super(timerService, identityService); - this.firmwareService = firmwareService; - } - - @Override - public Response getTargetFilters(RequestParams requestParams, Integer offset, Integer limit) { - return HawkbitResponse.proxy("Failed to retrieve firmware target filters", - () -> firmwareService.targetFiltersResource.getTargetFilters(offset, limit)).asPage(); - } - - @Override - public Response getTargetFilter(RequestParams requestParams, Long id) { - return HawkbitResponse.proxy("Failed to retrieve firmware target filter '" + id + "'", - () -> firmwareService.targetFiltersResource.get(id)).asResource(); - } - - @Override - public Response createTargetFilter(RequestParams requestParams, - FirmwareTargetFilterCreate filter) { - return HawkbitResponse.proxy("Failed to create firmware target filter", - () -> firmwareService.targetFiltersResource.create(filter)).asResource(); - } - - @Override - public void deleteTargetFilter(RequestParams requestParams, Long id) { - HawkbitResponse.proxy("Failed to delete firmware target filter '" + id + "'", - () -> firmwareService.targetFiltersResource.delete(id)); - } - - @Override - public Response getAutoAssignDS(RequestParams requestParams, Long id) { - return HawkbitResponse.proxy( - "Failed to retrieve auto assign distribution set for filter '" + id + "'", - () -> firmwareService.targetFiltersResource.getAutoAssignDS(id)).asResource(); - } - - @Override - public Response setAutoAssignDS(RequestParams requestParams, Long id, - FirmwareAutoAssignDS request) { - return HawkbitResponse.proxy( - "Failed to set auto assign distribution set for filter '" + id + "'", - () -> firmwareService.targetFiltersResource.setAutoAssignDS(id, request)).asResource(); - } - - @Override - public void deleteAutoAssignDS(RequestParams requestParams, Long id) { - HawkbitResponse.proxy( - "Failed to remove auto assign distribution set from filter '" + id + "'", - () -> firmwareService.targetFiltersResource.deleteAutoAssignDS(id)); - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java deleted file mode 100644 index 46e7267..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/HawkbitResponse.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.manager.firmware; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.openremote.model.util.ValueUtil; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Supplier; - -class HawkbitResponse { - - static HawkbitResponse proxy(String errorMessage, Supplier call) { - try { - return from(call.get()); - } catch (WebApplicationException e) { - throw e; - } catch (Exception e) { - throw new WebApplicationException(errorMessage, e, Response.Status.BAD_GATEWAY); - } - } - - static void proxy(String errorMessage, Runnable call) { - try { - call.run(); - } catch (WebApplicationException e) { - throw e; - } catch (Exception e) { - throw new WebApplicationException(errorMessage, e, Response.Status.BAD_GATEWAY); - } - } - - private record LinkMapping(String idField, String nameField) {} - - private static final Map DEFAULT_LINK_MAPPINGS = Map.of( - "distributionset", new LinkMapping("distributionSetId", "distributionSetName")); - - private final Response response; - private final Map linkMappings = new LinkedHashMap<>(DEFAULT_LINK_MAPPINGS); - - private HawkbitResponse(Response response) { - this.response = response; - } - - static HawkbitResponse from(Response response) { - return new HawkbitResponse(response); - } - - HawkbitResponse withLinkMapping(String rel, String idField, String nameField) { - linkMappings.put(rel, new LinkMapping(idField, nameField)); - return this; - } - - Response asResource() { - return formatResponse(Mode.HAL); - } - - Response asPage() { - return formatResponse(Mode.PAGED); - } - - Response raw() { - return response; - } - - private Response formatResponse(Mode mode) { - try (response) { - Response.ResponseBuilder builder = Response.status(response.getStatus()); - if (!response.hasEntity()) { - return builder.build(); - } - - String body = response.readEntity(String.class); - if (body == null || body.isBlank()) { - return builder.build(); - } - - try { - JsonNode formatted = switch (mode) { - case HAL -> stripHal(ValueUtil.JSON.readTree(body)); - case PAGED -> toPagedResponse(ValueUtil.JSON.readTree(body)); - }; - return builder - .type(MediaType.APPLICATION_JSON_TYPE) - .entity(ValueUtil.JSON.writeValueAsString(formatted)) - .build(); - } catch (Exception ignored) { - MediaType mediaType = response.getMediaType() == null - ? MediaType.TEXT_PLAIN_TYPE - : response.getMediaType(); - return builder.type(mediaType).entity(body).build(); - } - } catch (Exception e) { - throw new WebApplicationException("Failed to format hawkBit response", e, - Response.Status.BAD_GATEWAY); - } - } - - private ObjectNode toPagedResponse(JsonNode root) { - ArrayNode content = JsonNodeFactory.instance.arrayNode(); - if (root.isArray()) { - root.forEach(item -> content.add(stripHal(item))); - } else if (root.isObject() && root.has("_embedded")) { - embeddedContent(root.get("_embedded")).forEach(item -> content.add(stripHal(item))); - } else if (root.isObject() && root.path("content").isArray()) { - root.get("content").forEach(item -> content.add(stripHal(item))); - } else if (!root.isMissingNode() && !root.isNull()) { - content.add(stripHal(root)); - } - - ObjectNode formatted = JsonNodeFactory.instance.objectNode(); - formatted.set("content", content); - formatted.put("total", intValue(root, "total", intValue(root.path("page"), "totalElements", content.size()))); - formatted.put("size", intValue(root, "size", intValue(root.path("page"), "size", content.size()))); - return formatted; - } - - private JsonNode stripHal(JsonNode node) { - if (node.isArray()) { - ArrayNode formatted = JsonNodeFactory.instance.arrayNode(); - node.forEach(item -> formatted.add(stripHal(item))); - return formatted; - } - - if (!node.isObject()) { - return node; - } - - ObjectNode formatted = JsonNodeFactory.instance.objectNode(); - for (Map.Entry field : node.properties()) { - if ("_links".equals(field.getKey()) || "_embedded".equals(field.getKey())) { - continue; - } - formatted.set(field.getKey(), stripHal(field.getValue())); - } - addMappedLinkIds(node.path("_links"), formatted); - return formatted; - } - - private void addMappedLinkIds(JsonNode links, ObjectNode target) { - if (!links.isObject()) { - return; - } - - linkMappings.forEach((rel, mapping) -> { - JsonNode link = links.path(rel); - Long id = idFromHref(link.path("href")); - if (id != null && !target.has(mapping.idField())) { - target.put(mapping.idField(), id); - } - JsonNode name = link.path("name"); - if (name.isTextual() && !target.has(mapping.nameField())) { - target.put(mapping.nameField(), name.textValue()); - } - }); - } - - private static Long idFromHref(JsonNode hrefNode) { - if (!hrefNode.isTextual()) { - return null; - } - - String href = hrefNode.textValue(); - int end = href.endsWith("/") ? href.length() - 1 : href.length(); - int start = href.lastIndexOf('/', end - 1) + 1; - if (start >= end) { - return null; - } - try { - return Long.parseLong(href.substring(start, end)); - } catch (NumberFormatException ignored) { - return null; - } - } - - private static ArrayNode embeddedContent(JsonNode embedded) { - ArrayNode content = JsonNodeFactory.instance.arrayNode(); - if (!embedded.isObject()) { - return content; - } - - for (JsonNode value : embedded) { - if (value.isArray()) { - value.forEach(content::add); - return content; - } - } - return content; - } - - private static int intValue(JsonNode node, String field, int defaultValue) { - JsonNode value = node.path(field); - return value.isNumber() ? value.intValue() : defaultValue; - } - - private enum Mode { - HAL, - PAGED - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesClient.java similarity index 80% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesClient.java index c6cbb1e..703281a 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesClient.java @@ -19,27 +19,20 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypeCreate; +import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetTypeCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("distributionsettypes") -public interface HawkbitDistributionSetTypesResource { +public interface HawkbitDistributionSetTypesClient { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(FirmwareDistributionSetTypeCreate[] distributionSetTypes); + Response create(DistributionSetTypeCreateRequest[] distributionSetTypes); @GET @Produces(APPLICATION_JSON) @@ -67,5 +60,5 @@ Response getOptionalModuleTypes(@PathParam("id") Long id, @DELETE @Path("{id}") - void delete(@PathParam("id") Long id); + Response delete(@PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsClient.java similarity index 72% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsClient.java index d05a35b..3f44a14 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsClient.java @@ -19,28 +19,21 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetAssignment; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetCreate; +import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetAssignmentRequest; +import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("distributionsets") -public interface HawkbitDistributionSetsResource { +public interface HawkbitDistributionSetsClient { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(FirmwareDistributionSetCreate[] distributionSets); + Response create(DistributionSetCreateRequest[] distributionSets); @POST @Path("{id}/assignedTargets") @@ -48,7 +41,7 @@ public interface HawkbitDistributionSetsResource { @Produces(APPLICATION_HAL_JSON) Response assignTargets(@PathParam("id") Long id, @QueryParam("offline") Boolean offline, - FirmwareDistributionSetAssignment[] targets); + DistributionSetAssignmentRequest[] targets); @GET @Produces(APPLICATION_JSON) @@ -62,5 +55,5 @@ Response getDistributionSets(@QueryParam("offset") Integer offset, @DELETE @Path("{id}") - void delete(@PathParam("id") Long id); + Response delete(@PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsClient.java similarity index 82% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsClient.java index 9d529a0..1ca6d5c 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsClient.java @@ -19,22 +19,15 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutCreate; +import org.openremote.extension.hawkbit.model.hawkbit.RolloutCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("rollouts") -public interface HawkbitRolloutsResource { +public interface HawkbitRolloutsClient { @GET @Produces(APPLICATION_JSON) @@ -50,11 +43,11 @@ Response getRollouts(@QueryParam("offset") Integer offset, @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(FirmwareRolloutCreate rollout); + Response create(RolloutCreateRequest rollout); @DELETE @Path("{id}") - void delete(@PathParam("id") Long id); + Response delete(@PathParam("id") Long id); @POST @Path("{id}/start") @@ -63,7 +56,7 @@ Response getRollouts(@QueryParam("offset") Integer offset, @POST @Path("{id}/pause") - void pause(@PathParam("id") Long id); + Response pause(@PathParam("id") Long id); @GET @Path("{id}/deploygroups") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesClient.java similarity index 75% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesClient.java index 1d6802e..d7aba49 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesClient.java @@ -19,27 +19,20 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleTypeCreate; +import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleTypeCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("softwaremoduletypes") -public interface HawkbitSoftwareModuleTypesResource { +public interface HawkbitSoftwareModuleTypesClient { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(FirmwareSoftwareModuleTypeCreate[] softwareModuleTypes); + Response create(SoftwareModuleTypeCreateRequest[] softwareModuleTypes); @GET @Produces(APPLICATION_JSON) @@ -53,5 +46,5 @@ Response getSoftwareModuleTypes(@QueryParam("offset") Integer offset, @DELETE @Path("{id}") - void delete(@PathParam("id") Long id); + Response delete(@PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesClient.java similarity index 81% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesClient.java index 1a13948..4ee71e7 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesClient.java @@ -19,29 +19,22 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleCreate; +import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static jakarta.ws.rs.core.MediaType.MULTIPART_FORM_DATA; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("softwaremodules") -public interface HawkbitSoftwareModulesResource { +public interface HawkbitSoftwareModulesClient { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(FirmwareSoftwareModuleCreate[] softwareModules); + Response create(SoftwareModuleCreateRequest[] softwareModules); @GET @Produces(APPLICATION_JSON) @@ -68,6 +61,6 @@ Response uploadArtifact(@PathParam("id") Long id, @DELETE @Path("{id}") - void delete(@PathParam("id") Long id); + Response delete(@PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersClient.java similarity index 73% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersClient.java index bf0bbda..9de81aa 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersClient.java @@ -19,23 +19,16 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.firmware.FirmwareAutoAssignDS; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetFilterCreate; +import org.openremote.extension.hawkbit.model.hawkbit.AutoAssignDistributionSetRequest; +import org.openremote.extension.hawkbit.model.hawkbit.TargetFilterCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("targetfilters") -public interface HawkbitTargetFiltersResource { +public interface HawkbitTargetFiltersClient { @GET @Produces(APPLICATION_JSON) @@ -50,11 +43,11 @@ Response getTargetFilters(@QueryParam("offset") Integer offset, @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(FirmwareTargetFilterCreate filter); + Response create(TargetFilterCreateRequest filter); @DELETE @Path("{filterId}") - void delete(@PathParam("filterId") Long filterId); + Response delete(@PathParam("filterId") Long filterId); @GET @Path("{filterId}/autoAssignDS") @@ -66,9 +59,9 @@ Response getTargetFilters(@QueryParam("offset") Integer offset, @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) Response setAutoAssignDS(@PathParam("filterId") Long filterId, - FirmwareAutoAssignDS request); + AutoAssignDistributionSetRequest request); @DELETE @Path("{filterId}/autoAssignDS") - void deleteAutoAssignDS(@PathParam("filterId") Long filterId); + Response deleteAutoAssignDS(@PathParam("filterId") Long filterId); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsClient.java similarity index 74% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsClient.java index f93aa49..dbe8cc0 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsClient.java @@ -21,15 +21,16 @@ import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.firmware.FirmwareMetadataUpdate; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTarget; +import org.openremote.extension.hawkbit.model.hawkbit.MetadataUpdateRequest; +import org.openremote.extension.hawkbit.model.hawkbit.Target; +import org.openremote.extension.hawkbit.model.hawkbit.TargetCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @Path("targets") -public interface HawkbitTargetsResource { +public interface HawkbitTargetsClient { @GET @Produces(APPLICATION_JSON) Response getTargets(@QueryParam("q") String query, @QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit); @@ -37,7 +38,7 @@ public interface HawkbitTargetsResource { @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) - Response create(FirmwareTarget[] targets); + Response create(TargetCreateRequest[] targets); @GET @@ -49,11 +50,11 @@ public interface HawkbitTargetsResource { @Path("{id}") @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) - Response update(@PathParam("id") String id, FirmwareTarget target); + Response update(@PathParam("id") String id, Target target); @DELETE @Path("{id}") - void delete(@PathParam("id") String id); + Response delete(@PathParam("id") String id); @GET @Path("{id}/metadata") @@ -63,13 +64,13 @@ public interface HawkbitTargetsResource { @PUT @Path("{id}/metadata/{key}") @Consumes(APPLICATION_JSON) - void updateMetadata(@PathParam("id") String id, - @PathParam("key") String key, - FirmwareMetadataUpdate metadata); + Response updateMetadata(@PathParam("id") String id, + @PathParam("key") String key, + MetadataUpdateRequest metadata); @DELETE @Path("{id}/metadata/{key}") - void deleteMetadata(@PathParam("id") String id, @PathParam("key") String key); + Response deleteMetadata(@PathParam("id") String id, @PathParam("key") String key); @GET @Path("{id}/assignedDS") @@ -95,7 +96,7 @@ Response getActions(@PathParam("id") String id, @DELETE @Path("{id}/actions/{actionId}") - void cancelAction(@PathParam("id") String id, - @PathParam("actionId") Long actionId, - @QueryParam("force") Boolean force); + Response cancelAction(@PathParam("id") String id, + @PathParam("actionId") Long actionId, + @QueryParam("force") Boolean force); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java new file mode 100644 index 0000000..af85694 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.manager.resource; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import org.openremote.container.timer.TimerService; +import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; +import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; +import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetAssignmentRequest; +import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetCreateRequest; +import org.openremote.extension.hawkbit.model.resource.DistributionSetResource; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.manager.web.ManagerWebResource; +import org.openremote.model.http.RequestParams; + +public class DistributionSetResourceImpl extends ManagerWebResource + implements DistributionSetResource { + + protected final HawkbitFirmwareService hawkbitFirmwareService; + + public DistributionSetResourceImpl(TimerService timerService, ManagerIdentityService identityService, + HawkbitFirmwareService hawkbitFirmwareService) { + super(timerService, identityService); + this.hawkbitFirmwareService = hawkbitFirmwareService; + } + + @Override + public Response createDistributionSet(RequestParams requestParams, + DistributionSetCreateRequest distributionSet) { + return HawkbitResponseHandler.call("Failed to create firmware distribution set", + () -> hawkbitFirmwareService.distributionSets().create( + new DistributionSetCreateRequest[]{distributionSet})); + } + + @Override + public Response assignDistributionSet(RequestParams requestParams, Long id, + Boolean offline, + DistributionSetAssignmentRequest[] targets) { + if (targets == null || targets.length == 0) { + throw new WebApplicationException("Assignment requires at least one target", Response.Status.BAD_REQUEST); + } + return HawkbitResponseHandler.call("Failed to assign firmware distribution set '" + id + "'", + () -> hawkbitFirmwareService.distributionSets().assignTargets(id, offline, targets)); + } + + @Override + public Response getDistributionSets(RequestParams requestParams, Integer offset, Integer limit) { + return HawkbitResponseHandler.call("Failed to retrieve firmware distribution sets", + () -> hawkbitFirmwareService.distributionSets().getDistributionSets(offset, limit)); + } + + @Override + public Response getDistributionSet(RequestParams requestParams, Long id) { + return HawkbitResponseHandler.call("Failed to retrieve firmware distribution set '" + id + "'", + () -> hawkbitFirmwareService.distributionSets().get(id)); + } + + @Override + public void deleteDistributionSet(RequestParams requestParams, Long id) { + HawkbitResponseHandler.call("Failed to delete firmware distribution set '" + id + "'", + () -> hawkbitFirmwareService.distributionSets().delete(id)); + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java similarity index 50% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java index d4742b4..cd21894 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareDistributionSetTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java @@ -17,68 +17,70 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.manager.firmware; +package org.openremote.extension.hawkbit.manager.resource; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; +import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; +import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; +import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetTypeCreateRequest; +import org.openremote.extension.hawkbit.model.resource.DistributionSetTypeResource; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypeCreate; -import org.openremote.extension.hawkbit.model.firmware.FirmwareDistributionSetTypeResource; -public class FirmwareDistributionSetTypeResourceImpl extends ManagerWebResource - implements FirmwareDistributionSetTypeResource { +public class DistributionSetTypeResourceImpl extends ManagerWebResource + implements DistributionSetTypeResource { - protected final FirmwareService firmwareService; + protected final HawkbitFirmwareService hawkbitFirmwareService; - public FirmwareDistributionSetTypeResourceImpl(TimerService timerService, - ManagerIdentityService identityService, - FirmwareService firmwareService) { + public DistributionSetTypeResourceImpl(TimerService timerService, + ManagerIdentityService identityService, + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService); - this.firmwareService = firmwareService; + this.hawkbitFirmwareService = hawkbitFirmwareService; } @Override public Response createDistributionSetType(RequestParams requestParams, - FirmwareDistributionSetTypeCreate distributionSetType) { - return HawkbitResponse.proxy("Failed to create firmware distribution set type", - () -> firmwareService.distributionSetTypesResource.create( - new FirmwareDistributionSetTypeCreate[] { distributionSetType })).asResource(); + DistributionSetTypeCreateRequest distributionSetType) { + return HawkbitResponseHandler.call("Failed to create firmware distribution set type", + () -> hawkbitFirmwareService.distributionSetTypes().create( + new DistributionSetTypeCreateRequest[]{distributionSetType})); } @Override public Response getDistributionSetTypes(RequestParams requestParams, Integer offset, Integer limit) { - return HawkbitResponse.proxy("Failed to retrieve firmware distribution set types", - () -> firmwareService.distributionSetTypesResource.getDistributionSetTypes(offset, limit)).asPage(); + return HawkbitResponseHandler.call("Failed to retrieve firmware distribution set types", + () -> hawkbitFirmwareService.distributionSetTypes().getDistributionSetTypes(offset, limit)); } @Override public Response getDistributionSetType(RequestParams requestParams, Long id) { - return HawkbitResponse.proxy("Failed to retrieve firmware distribution set type '" + id + "'", - () -> firmwareService.distributionSetTypesResource.get(id)).asResource(); + return HawkbitResponseHandler.call("Failed to retrieve firmware distribution set type '" + id + "'", + () -> hawkbitFirmwareService.distributionSetTypes().get(id)); } @Override public Response getMandatoryModuleTypes(RequestParams requestParams, Long id, Integer offset, Integer limit) { - return HawkbitResponse.proxy( + return HawkbitResponseHandler.call( "Failed to retrieve mandatory module types for firmware distribution set type '" + id + "'", - () -> firmwareService.distributionSetTypesResource.getMandatoryModuleTypes(id, offset, limit)).asPage(); + () -> hawkbitFirmwareService.distributionSetTypes().getMandatoryModuleTypes(id, offset, limit)); } @Override public Response getOptionalModuleTypes(RequestParams requestParams, Long id, Integer offset, Integer limit) { - return HawkbitResponse.proxy( + return HawkbitResponseHandler.call( "Failed to retrieve optional module types for firmware distribution set type '" + id + "'", - () -> firmwareService.distributionSetTypesResource.getOptionalModuleTypes(id, offset, limit)).asPage(); + () -> hawkbitFirmwareService.distributionSetTypes().getOptionalModuleTypes(id, offset, limit)); } @Override public void deleteDistributionSetType(RequestParams requestParams, Long id) { - HawkbitResponse.proxy("Failed to delete firmware distribution set type '" + id + "'", - () -> firmwareService.distributionSetTypesResource.delete(id)); + HawkbitResponseHandler.call("Failed to delete firmware distribution set type '" + id + "'", + () -> hawkbitFirmwareService.distributionSetTypes().delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java similarity index 50% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java index 4130940..7c62865 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareRolloutResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java @@ -17,75 +17,77 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.manager.firmware; +package org.openremote.extension.hawkbit.manager.resource; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; +import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; +import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; +import org.openremote.extension.hawkbit.model.hawkbit.RolloutCreateRequest; +import org.openremote.extension.hawkbit.model.resource.RolloutResource; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutCreate; -import org.openremote.extension.hawkbit.model.firmware.FirmwareRolloutResource; import org.openremote.model.http.RequestParams; -public class FirmwareRolloutResourceImpl extends ManagerWebResource - implements FirmwareRolloutResource { +public class RolloutResourceImpl extends ManagerWebResource + implements RolloutResource { - protected final FirmwareService firmwareService; + protected final HawkbitFirmwareService hawkbitFirmwareService; - public FirmwareRolloutResourceImpl(TimerService timerService, ManagerIdentityService identityService, - FirmwareService firmwareService) { + public RolloutResourceImpl(TimerService timerService, ManagerIdentityService identityService, + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService); - this.firmwareService = firmwareService; + this.hawkbitFirmwareService = hawkbitFirmwareService; } @Override public Response getRollouts(RequestParams requestParams, Integer offset, Integer limit) { // Request full representation so totalTargetsPerStatus and totalGroups are populated; hawkBit defaults to compact. - return HawkbitResponse.proxy("Failed to retrieve firmware rollouts", - () -> firmwareService.rolloutsResource.getRollouts(offset, limit, "full")).asPage(); + return HawkbitResponseHandler.call("Failed to retrieve firmware rollouts", + () -> hawkbitFirmwareService.rollouts().getRollouts(offset, limit, "full")); } @Override public Response getRollout(RequestParams requestParams, Long id) { - return HawkbitResponse.proxy("Failed to retrieve firmware rollout '" + id + "'", - () -> firmwareService.rolloutsResource.get(id)).asResource(); + return HawkbitResponseHandler.call("Failed to retrieve firmware rollout '" + id + "'", + () -> hawkbitFirmwareService.rollouts().get(id)); } @Override - public Response createRollout(RequestParams requestParams, FirmwareRolloutCreate rollout) { - return HawkbitResponse.proxy("Failed to create firmware rollout", - () -> firmwareService.rolloutsResource.create(rollout)).asResource(); + public Response createRollout(RequestParams requestParams, RolloutCreateRequest rollout) { + return HawkbitResponseHandler.call("Failed to create firmware rollout", + () -> hawkbitFirmwareService.rollouts().create(rollout)); } @Override public void deleteRollout(RequestParams requestParams, Long id) { - HawkbitResponse.proxy("Failed to delete firmware rollout '" + id + "'", - () -> firmwareService.rolloutsResource.delete(id)); + HawkbitResponseHandler.call("Failed to delete firmware rollout '" + id + "'", + () -> hawkbitFirmwareService.rollouts().delete(id)); } @Override public Response startRollout(RequestParams requestParams, Long id) { - return HawkbitResponse.proxy("Failed to start firmware rollout '" + id + "'", - () -> firmwareService.rolloutsResource.start(id)).asResource(); + return HawkbitResponseHandler.call("Failed to start firmware rollout '" + id + "'", + () -> hawkbitFirmwareService.rollouts().start(id)); } @Override public void pauseRollout(RequestParams requestParams, Long id) { - HawkbitResponse.proxy("Failed to pause firmware rollout '" + id + "'", - () -> firmwareService.rolloutsResource.pause(id)); + HawkbitResponseHandler.call("Failed to pause firmware rollout '" + id + "'", + () -> hawkbitFirmwareService.rollouts().pause(id)); } @Override public Response getRolloutGroups(RequestParams requestParams, Long id, Integer offset, Integer limit) { - return HawkbitResponse.proxy("Failed to retrieve groups for rollout '" + id + "'", - () -> firmwareService.rolloutsResource.getRolloutGroups(id, offset, limit, "full")).asPage(); + return HawkbitResponseHandler.call("Failed to retrieve groups for rollout '" + id + "'", + () -> hawkbitFirmwareService.rollouts().getRolloutGroups(id, offset, limit, "full")); } @Override public Response getRolloutGroup(RequestParams requestParams, Long id, Long groupId) { - return HawkbitResponse.proxy( + return HawkbitResponseHandler.call( "Failed to retrieve group '" + groupId + "' for rollout '" + id + "'", - () -> firmwareService.rolloutsResource.getRolloutGroup(id, groupId)).asResource(); + () -> hawkbitFirmwareService.rollouts().getRolloutGroup(id, groupId)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java similarity index 59% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java index 60156ee..9385794 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareSoftwareModuleResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java @@ -17,56 +17,58 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.manager.firmware; +package org.openremote.extension.hawkbit.manager.resource; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.EntityPart; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; +import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; +import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; +import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleCreateRequest; +import org.openremote.extension.hawkbit.model.resource.SoftwareModuleResource; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleCreate; -import org.openremote.extension.hawkbit.model.firmware.FirmwareSoftwareModuleResource; import java.io.InputStream; import java.util.List; -public class FirmwareSoftwareModuleResourceImpl extends ManagerWebResource - implements FirmwareSoftwareModuleResource { +public class SoftwareModuleResourceImpl extends ManagerWebResource + implements SoftwareModuleResource { - protected final FirmwareService firmwareService; + protected final HawkbitFirmwareService hawkbitFirmwareService; - public FirmwareSoftwareModuleResourceImpl(TimerService timerService, ManagerIdentityService identityService, - FirmwareService firmwareService) { + public SoftwareModuleResourceImpl(TimerService timerService, ManagerIdentityService identityService, + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService); - this.firmwareService = firmwareService; + this.hawkbitFirmwareService = hawkbitFirmwareService; } @Override public Response createSoftwareModule(RequestParams requestParams, - FirmwareSoftwareModuleCreate softwareModule) { - return HawkbitResponse.proxy("Failed to create firmware software module", - () -> firmwareService.softwareModulesResource.create( - new FirmwareSoftwareModuleCreate[] { softwareModule })).asResource(); + SoftwareModuleCreateRequest softwareModule) { + return HawkbitResponseHandler.call("Failed to create firmware software module", + () -> hawkbitFirmwareService.softwareModules().create( + new SoftwareModuleCreateRequest[]{softwareModule})); } @Override public Response getSoftwareModules(RequestParams requestParams, Integer offset, Integer limit) { - return HawkbitResponse.proxy("Failed to retrieve firmware software modules", - () -> firmwareService.softwareModulesResource.getSoftwareModules(offset, limit)).asPage(); + return HawkbitResponseHandler.call("Failed to retrieve firmware software modules", + () -> hawkbitFirmwareService.softwareModules().getSoftwareModules(offset, limit)); } @Override public Response getSoftwareModule(RequestParams requestParams, Long id) { - return HawkbitResponse.proxy("Failed to retrieve firmware software module '" + id + "'", - () -> firmwareService.softwareModulesResource.get(id)).asResource(); + return HawkbitResponseHandler.call("Failed to retrieve firmware software module '" + id + "'", + () -> hawkbitFirmwareService.softwareModules().get(id)); } @Override public Response getSoftwareModuleArtifacts(RequestParams requestParams, Long id) { - return HawkbitResponse.proxy("Failed to retrieve artifacts for firmware software module '" + id + "'", - () -> firmwareService.softwareModulesResource.getArtifacts(id)).asPage(); + return HawkbitResponseHandler.call("Failed to retrieve artifacts for firmware software module '" + id + "'", + () -> hawkbitFirmwareService.softwareModules().getArtifacts(id)); } @Override @@ -85,7 +87,7 @@ public Response uploadSoftwareModuleArtifact(RequestParams requestParams, String submittedFileName = filePart.getFileName().orElse(null); InputStream inputStream = filePart.getContent(InputStream.class); - return firmwareService.uploadSoftwareModuleArtifact(id, inputStream, submittedFileName, filename); + return hawkbitFirmwareService.uploadSoftwareModuleArtifact(id, inputStream, submittedFileName, filename); } catch (WebApplicationException e) { throw e; } catch (Exception e) { @@ -96,7 +98,7 @@ public Response uploadSoftwareModuleArtifact(RequestParams requestParams, @Override public void deleteSoftwareModule(RequestParams requestParams, Long id) { - HawkbitResponse.proxy("Failed to delete firmware software module '" + id + "'", - () -> firmwareService.softwareModulesResource.delete(id)); + HawkbitResponseHandler.call("Failed to delete firmware software module '" + id + "'", + () -> hawkbitFirmwareService.softwareModules().delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java new file mode 100644 index 0000000..734e1e4 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java @@ -0,0 +1,69 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.manager.resource; + +import jakarta.ws.rs.core.Response; +import org.openremote.container.timer.TimerService; +import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; +import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; +import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleTypeCreateRequest; +import org.openremote.extension.hawkbit.model.resource.SoftwareModuleTypeResource; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.manager.web.ManagerWebResource; +import org.openremote.model.http.RequestParams; + +public class SoftwareModuleTypeResourceImpl extends ManagerWebResource + implements SoftwareModuleTypeResource { + + protected final HawkbitFirmwareService hawkbitFirmwareService; + + public SoftwareModuleTypeResourceImpl(TimerService timerService, ManagerIdentityService identityService, + HawkbitFirmwareService hawkbitFirmwareService) { + super(timerService, identityService); + this.hawkbitFirmwareService = hawkbitFirmwareService; + } + + @Override + public Response createSoftwareModuleType(RequestParams requestParams, + SoftwareModuleTypeCreateRequest softwareModuleType) { + return HawkbitResponseHandler.call("Failed to create firmware software module type", + () -> hawkbitFirmwareService.softwareModuleTypes().create( + new SoftwareModuleTypeCreateRequest[]{softwareModuleType})); + } + + @Override + public Response getSoftwareModuleTypes(RequestParams requestParams, Integer offset, + Integer limit) { + return HawkbitResponseHandler.call("Failed to retrieve firmware software module types", + () -> hawkbitFirmwareService.softwareModuleTypes().getSoftwareModuleTypes(offset, limit)); + } + + @Override + public Response getSoftwareModuleType(RequestParams requestParams, Long id) { + return HawkbitResponseHandler.call("Failed to retrieve firmware software module type '" + id + "'", + () -> hawkbitFirmwareService.softwareModuleTypes().get(id)); + } + + @Override + public void deleteSoftwareModuleType(RequestParams requestParams, Long id) { + HawkbitResponseHandler.call("Failed to delete firmware software module type '" + id + "'", + () -> hawkbitFirmwareService.softwareModuleTypes().delete(id)); + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java new file mode 100644 index 0000000..cd6922f --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java @@ -0,0 +1,90 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.manager.resource; + +import jakarta.ws.rs.core.Response; +import org.openremote.container.timer.TimerService; +import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; +import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; +import org.openremote.extension.hawkbit.model.hawkbit.AutoAssignDistributionSetRequest; +import org.openremote.extension.hawkbit.model.hawkbit.TargetFilterCreateRequest; +import org.openremote.extension.hawkbit.model.resource.TargetFilterResource; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.manager.web.ManagerWebResource; +import org.openremote.model.http.RequestParams; + +public class TargetFilterResourceImpl extends ManagerWebResource + implements TargetFilterResource { + + protected final HawkbitFirmwareService hawkbitFirmwareService; + + public TargetFilterResourceImpl(TimerService timerService, ManagerIdentityService identityService, + HawkbitFirmwareService hawkbitFirmwareService) { + super(timerService, identityService); + this.hawkbitFirmwareService = hawkbitFirmwareService; + } + + @Override + public Response getTargetFilters(RequestParams requestParams, Integer offset, Integer limit) { + return HawkbitResponseHandler.call("Failed to retrieve firmware target filters", + () -> hawkbitFirmwareService.targetFilters().getTargetFilters(offset, limit)); + } + + @Override + public Response getTargetFilter(RequestParams requestParams, Long id) { + return HawkbitResponseHandler.call("Failed to retrieve firmware target filter '" + id + "'", + () -> hawkbitFirmwareService.targetFilters().get(id)); + } + + @Override + public Response createTargetFilter(RequestParams requestParams, + TargetFilterCreateRequest filter) { + return HawkbitResponseHandler.call("Failed to create firmware target filter", + () -> hawkbitFirmwareService.targetFilters().create(filter)); + } + + @Override + public void deleteTargetFilter(RequestParams requestParams, Long id) { + HawkbitResponseHandler.call("Failed to delete firmware target filter '" + id + "'", + () -> hawkbitFirmwareService.targetFilters().delete(id)); + } + + @Override + public Response getAutoAssignDS(RequestParams requestParams, Long id) { + return HawkbitResponseHandler.call( + "Failed to retrieve auto assign distribution set for filter '" + id + "'", + () -> hawkbitFirmwareService.targetFilters().getAutoAssignDS(id)); + } + + @Override + public Response setAutoAssignDS(RequestParams requestParams, Long id, + AutoAssignDistributionSetRequest request) { + return HawkbitResponseHandler.call( + "Failed to set auto assign distribution set for filter '" + id + "'", + () -> hawkbitFirmwareService.targetFilters().setAutoAssignDS(id, request)); + } + + @Override + public void deleteAutoAssignDS(RequestParams requestParams, Long id) { + HawkbitResponseHandler.call( + "Failed to remove auto assign distribution set from filter '" + id + "'", + () -> hawkbitFirmwareService.targetFilters().deleteAutoAssignDS(id)); + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java similarity index 52% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java index 3f205b9..74a3d79 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/firmware/FirmwareTargetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java @@ -17,72 +17,74 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.manager.firmware; +package org.openremote.extension.hawkbit.manager.resource; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; +import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; +import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; +import org.openremote.extension.hawkbit.model.resource.TargetResource; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -import org.openremote.extension.hawkbit.model.firmware.FirmwareTargetResource; -public class FirmwareTargetResourceImpl extends ManagerWebResource implements FirmwareTargetResource { +public class TargetResourceImpl extends ManagerWebResource implements TargetResource { - protected final FirmwareService firmwareService; + protected final HawkbitFirmwareService hawkbitFirmwareService; - public FirmwareTargetResourceImpl(TimerService timerService, ManagerIdentityService identityService, - FirmwareService firmwareService) { + public TargetResourceImpl(TimerService timerService, ManagerIdentityService identityService, + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService); - this.firmwareService = firmwareService; + this.hawkbitFirmwareService = hawkbitFirmwareService; } @Override public Response getTargets(RequestParams requestParams, String query, Integer offset, Integer limit) { - return HawkbitResponse.proxy("Failed to retrieve firmware targets", - () -> firmwareService.targetsResource.getTargets(query, offset, limit)).asPage(); + return HawkbitResponseHandler.call("Failed to retrieve firmware targets", + () -> hawkbitFirmwareService.targets().getTargets(query, offset, limit)); } @Override public Response getTarget(RequestParams requestParams, String id) { - return HawkbitResponse.proxy("Failed to retrieve firmware target '" + id + "'", - () -> firmwareService.targetsResource.get(id)).asResource(); + return HawkbitResponseHandler.call("Failed to retrieve firmware target '" + id + "'", + () -> hawkbitFirmwareService.targets().get(id)); } @Override public Response getMetadata(RequestParams requestParams, String id) { - return HawkbitResponse.proxy("Failed to retrieve metadata for firmware target '" + id + "'", - () -> firmwareService.targetsResource.getMetadata(id)).asPage(); + return HawkbitResponseHandler.call("Failed to retrieve metadata for firmware target '" + id + "'", + () -> hawkbitFirmwareService.targets().getMetadata(id)); } @Override public Response getAssignedDs(RequestParams requestParams, String id) { - return HawkbitResponse.proxy("Failed to retrieve assigned DS for firmware target '" + id + "'", - () -> firmwareService.targetsResource.getAssignedDs(id)).asResource(); + return HawkbitResponseHandler.call("Failed to retrieve assigned DS for firmware target '" + id + "'", + () -> hawkbitFirmwareService.targets().getAssignedDs(id)); } @Override public Response getInstalledDs(RequestParams requestParams, String id) { - return HawkbitResponse.proxy("Failed to retrieve installed DS for firmware target '" + id + "'", - () -> firmwareService.targetsResource.getInstalledDs(id)).asResource(); + return HawkbitResponseHandler.call("Failed to retrieve installed DS for firmware target '" + id + "'", + () -> hawkbitFirmwareService.targets().getInstalledDs(id)); } @Override public Response getActions(RequestParams requestParams, String id, Integer offset, Integer limit) { - return HawkbitResponse.proxy("Failed to retrieve actions for firmware target '" + id + "'", - () -> firmwareService.targetsResource.getActions(id, offset, limit)).asPage(); + return HawkbitResponseHandler.call("Failed to retrieve actions for firmware target '" + id + "'", + () -> hawkbitFirmwareService.targets().getActions(id, offset, limit)); } @Override public Response getAction(RequestParams requestParams, String id, Long actionId) { - return HawkbitResponse.proxy( + return HawkbitResponseHandler.call( "Failed to retrieve action '" + actionId + "' for firmware target '" + id + "'", - () -> firmwareService.targetsResource.getAction(id, actionId)).asResource(); + () -> hawkbitFirmwareService.targets().getAction(id, actionId)); } @Override public void cancelAction(RequestParams requestParams, String id, Long actionId, Boolean force) { - HawkbitResponse.proxy( + HawkbitResponseHandler.call( "Failed to cancel action '" + actionId + "' for firmware target '" + id + "'", - () -> firmwareService.targetsResource.cancelAction(id, actionId, force)); + () -> hawkbitFirmwareService.targets().cancelAction(id, actionId, force)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/FirmwareMetaItemType.java similarity index 97% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/FirmwareMetaItemType.java index ebdc112..dc9d268 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetaItemType.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/FirmwareMetaItemType.java @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model; import org.openremote.model.util.TsIgnore; import org.openremote.model.value.MetaItemDescriptor; @@ -26,9 +26,6 @@ @TsIgnore public final class FirmwareMetaItemType { - private FirmwareMetaItemType() { - } - /** * Can be used on a {@link ValueType#TEXT} attribute to indicate that the parent asset should be synced as a * firmware target to hawkBit, enabling firmware updates and DDI interactions. The attribute value will be @@ -36,7 +33,6 @@ private FirmwareMetaItemType() { */ public static final MetaItemDescriptor FIRMWARE_TARGET = new MetaItemDescriptor<>( "firmwareTarget", ValueType.BOOLEAN); - /** * Can be used on any attribute to indicate that this attribute should be synced as metadata to the corresponding * target in hawkBit, enabling hawkBit target filters on specific metadata values. @@ -45,4 +41,7 @@ private FirmwareMetaItemType() { public static final MetaItemDescriptor FIRMWARE_METADATA = new MetaItemDescriptor<>( "firmwareMetadata", ValueType.BOOLEAN); + private FirmwareMetaItemType() { + } + } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModelProvider.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/FirmwareModelProvider.java similarity index 96% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModelProvider.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/FirmwareModelProvider.java index 4d9b449..1a19d27 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModelProvider.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/FirmwareModelProvider.java @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model; import org.openremote.model.AssetModelProvider; import org.openremote.model.asset.Asset; diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignDS.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/AutoAssignDistributionSetRequest.java similarity index 90% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignDS.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/AutoAssignDistributionSetRequest.java index dbd052e..eec1090 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareAutoAssignDS.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/AutoAssignDistributionSetRequest.java @@ -17,12 +17,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareAutoAssignDS( +public record AutoAssignDistributionSetRequest( Long id, String type, Integer weight, diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetAssignmentRequest.java similarity index 90% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetAssignmentRequest.java index f084aa3..af65ef6 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetAssignment.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetAssignmentRequest.java @@ -17,12 +17,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareDistributionSetAssignment( +public record DistributionSetAssignmentRequest( String id, String type, Long forcetime, diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetCreateRequest.java similarity index 87% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetCreate.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetCreateRequest.java index d5e4440..38e7977 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetCreate.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetCreateRequest.java @@ -17,15 +17,15 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareDistributionSetCreate( +public record DistributionSetCreateRequest( String name, String version, String type, String description, - FirmwareModuleReference[] modules) { + SoftwareModuleReferenceRequest[] modules) { } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetTypeCreateRequest.java similarity index 81% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeCreate.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetTypeCreateRequest.java index f78cfc4..1e6e0f6 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeCreate.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetTypeCreateRequest.java @@ -17,15 +17,15 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareDistributionSetTypeCreate( +public record DistributionSetTypeCreateRequest( String name, String key, String description, - FirmwareModuleReference[] mandatorymodules, - FirmwareModuleReference[] optionalmodules) { + SoftwareModuleReferenceRequest[] mandatorymodules, + SoftwareModuleReferenceRequest[] optionalmodules) { } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModuleReference.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/MetadataUpdateRequest.java similarity index 89% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModuleReference.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/MetadataUpdateRequest.java index 3eadb6f..a972c17 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareModuleReference.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/MetadataUpdateRequest.java @@ -17,10 +17,10 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareModuleReference(Long id) { +public record MetadataUpdateRequest(String value) { } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutActionRequest.java similarity index 87% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterCreate.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutActionRequest.java index 2324e76..4bde20d 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterCreate.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutActionRequest.java @@ -17,10 +17,10 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareTargetFilterCreate(String name, String query) { +public record RolloutActionRequest(String action, String expression) { } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutConditionRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutConditionRequest.java new file mode 100644 index 0000000..0077489 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutConditionRequest.java @@ -0,0 +1,26 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.hawkbit; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record RolloutConditionRequest(String condition, String expression) { +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutCreateRequest.java similarity index 80% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCreate.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutCreateRequest.java index 65a655d..33d92a5 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCreate.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutCreateRequest.java @@ -17,12 +17,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareRolloutCreate( +public record RolloutCreateRequest( String name, String description, String targetFilterQuery, @@ -32,9 +32,9 @@ public record FirmwareRolloutCreate( Long startAt, Integer weight, String type, - FirmwareRolloutCondition successCondition, - FirmwareRolloutAction successAction, - FirmwareRolloutCondition errorCondition, - FirmwareRolloutAction errorAction, + RolloutConditionRequest successCondition, + RolloutActionRequest successAction, + RolloutConditionRequest errorCondition, + RolloutActionRequest errorAction, Boolean confirmationRequired) { } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleCreateRequest.java similarity index 91% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleCreate.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleCreateRequest.java index 5591f41..e5e040e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleCreate.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleCreateRequest.java @@ -17,12 +17,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareSoftwareModuleCreate( +public record SoftwareModuleCreateRequest( String name, String version, String type, diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataUpdate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleReferenceRequest.java similarity index 89% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataUpdate.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleReferenceRequest.java index 7a1da9a..d7d11fb 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareMetadataUpdate.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleReferenceRequest.java @@ -17,10 +17,10 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareMetadataUpdate(String value) { +public record SoftwareModuleReferenceRequest(Long id) { } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeCreate.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleTypeCreateRequest.java similarity index 90% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeCreate.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleTypeCreateRequest.java index e7a8318..75d18cc 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeCreate.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleTypeCreateRequest.java @@ -17,12 +17,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareSoftwareModuleTypeCreate( +public record SoftwareModuleTypeCreateRequest( String name, String key, String description, diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/Target.java similarity index 82% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/Target.java index a005a8b..942901e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTarget.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/Target.java @@ -17,12 +17,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareTarget( +public record Target( String controllerId, String name, String description, @@ -36,8 +36,4 @@ public record FirmwareTarget( Long targetType, String targetTypeName, Boolean autoConfirmActive) { - - public FirmwareTarget(String controllerId, String name, String description) { - this(controllerId, name, description, null, null, null, null, null, null, null, null, null, null); - } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetCreateRequest.java similarity index 86% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetCreateRequest.java index 9245c47..155dd54 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutCondition.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetCreateRequest.java @@ -17,10 +17,10 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareRolloutCondition(String condition, String expression) { +public record TargetCreateRequest(String controllerId, String name, String description) { } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetFilterCreateRequest.java similarity index 87% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetFilterCreateRequest.java index 022905f..0876a5f 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutAction.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetFilterCreateRequest.java @@ -17,10 +17,10 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.hawkbit; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record FirmwareRolloutAction(String action, String expression) { +public record TargetFilterCreateRequest(String name, String query) { } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java similarity index 82% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java index 78b6168..017a8f9 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java @@ -17,21 +17,14 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.resource; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; -import jakarta.ws.rs.BeanParam; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; - +import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetAssignmentRequest; +import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -39,14 +32,14 @@ @Tag(name = "Firmware Distribution Sets", description = "Management of firmware distribution sets") @Path("firmware/distributionset") -public interface FirmwareDistributionSetResource { +public interface DistributionSetResource { @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createDistributionSet(@BeanParam RequestParams requestParams, - FirmwareDistributionSetCreate distributionSet); + DistributionSetCreateRequest distributionSet); @POST @Path("{id}/assign") @@ -56,7 +49,7 @@ Response createDistributionSet(@BeanParam RequestParams requestParams, Response assignDistributionSet(@BeanParam RequestParams requestParams, @PathParam("id") Long id, @QueryParam("offline") Boolean offline, - FirmwareDistributionSetAssignment[] targets); + DistributionSetAssignmentRequest[] targets); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java similarity index 86% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java index 4716009..b10fd83 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareDistributionSetTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java @@ -17,21 +17,13 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.resource; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; -import jakarta.ws.rs.BeanParam; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; - +import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetTypeCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -39,14 +31,14 @@ @Tag(name = "Firmware Distribution Set Types", description = "Management of firmware distribution set types") @Path("firmware/distributionsettype") -public interface FirmwareDistributionSetTypeResource { +public interface DistributionSetTypeResource { @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createDistributionSetType(@BeanParam RequestParams requestParams, - FirmwareDistributionSetTypeCreate distributionSetType); + DistributionSetTypeCreateRequest distributionSetType); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java similarity index 86% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java index c76aaed..e5edf5d 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareRolloutResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java @@ -17,21 +17,13 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.resource; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; -import jakarta.ws.rs.BeanParam; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; - +import org.openremote.extension.hawkbit.model.hawkbit.RolloutCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -39,7 +31,7 @@ @Tag(name = "Firmware Rollouts", description = "Management of firmware rollouts") @Path("firmware/rollout") -public interface FirmwareRolloutResource { +public interface RolloutResource { @GET @Produces(APPLICATION_JSON) @@ -60,13 +52,13 @@ Response getRollout(@BeanParam RequestParams requestParams, @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createRollout(@BeanParam RequestParams requestParams, - FirmwareRolloutCreate rollout); + RolloutCreateRequest rollout); @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) void deleteRollout(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + @PathParam("id") Long id); @POST @Path("{id}/start") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java similarity index 86% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java index fa14fbb..566c3fc 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java @@ -17,22 +17,14 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.resource; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; -import jakarta.ws.rs.BeanParam; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.EntityPart; import jakarta.ws.rs.core.Response; - +import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -43,14 +35,14 @@ @Tag(name = "Firmware Software Modules", description = "Management of firmware software modules") @Path("firmware/softwaremodule") -public interface FirmwareSoftwareModuleResource { +public interface SoftwareModuleResource { @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createSoftwareModule(@BeanParam RequestParams requestParams, - FirmwareSoftwareModuleCreate softwareModule); + SoftwareModuleCreateRequest softwareModule); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java similarity index 82% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java index 6fd3293..1e86634 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareSoftwareModuleTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java @@ -17,21 +17,13 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.resource; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; -import jakarta.ws.rs.BeanParam; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; - +import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleTypeCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -39,14 +31,14 @@ @Tag(name = "Firmware Software Module Types", description = "Management of firmware software module types") @Path("firmware/softwaremoduletype") -public interface FirmwareSoftwareModuleTypeResource { +public interface SoftwareModuleTypeResource { @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createSoftwareModuleType(@BeanParam RequestParams requestParams, - FirmwareSoftwareModuleTypeCreate softwareModuleType); + SoftwareModuleTypeCreateRequest softwareModuleType); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java similarity index 81% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java index 8afdca5..1a74b0e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetFilterResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java @@ -17,21 +17,14 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.resource; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; -import jakarta.ws.rs.BeanParam; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; - +import org.openremote.extension.hawkbit.model.hawkbit.AutoAssignDistributionSetRequest; +import org.openremote.extension.hawkbit.model.hawkbit.TargetFilterCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -39,7 +32,7 @@ @Tag(name = "Firmware Target Filters", description = "Management of firmware target filter queries") @Path("firmware/targetfilter") -public interface FirmwareTargetFilterResource { +public interface TargetFilterResource { @GET @Produces(APPLICATION_JSON) @@ -60,13 +53,13 @@ Response getTargetFilter(@BeanParam RequestParams requestParams, @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createTargetFilter(@BeanParam RequestParams requestParams, - FirmwareTargetFilterCreate filter); + TargetFilterCreateRequest filter); @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) void deleteTargetFilter(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + @PathParam("id") Long id); @GET @Path("{id}/autoAssignDS") @@ -82,11 +75,11 @@ Response getAutoAssignDS(@BeanParam RequestParams requestParams, @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response setAutoAssignDS(@BeanParam RequestParams requestParams, @PathParam("id") Long id, - FirmwareAutoAssignDS request); + AutoAssignDistributionSetRequest request); @DELETE @Path("{id}/autoAssignDS") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) void deleteAutoAssignDS(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + @PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java similarity index 91% rename from hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java rename to hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java index cacd843..5e7d5c3 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/firmware/FirmwareTargetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java @@ -17,27 +17,20 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.openremote.extension.hawkbit.model.firmware; +package org.openremote.extension.hawkbit.model.resource; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; -import jakarta.ws.rs.BeanParam; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; - import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; -import io.swagger.v3.oas.annotations.tags.Tag; @Tag(name = "Firmware Targets", description = "Management of firmware targets") @Path("firmware/target") -public interface FirmwareTargetResource { +public interface TargetResource { @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/resources/META-INF/services/org.openremote.model.AssetModelProvider b/hawkbit/src/main/resources/META-INF/services/org.openremote.model.AssetModelProvider index cd197f1..ac20c07 100644 --- a/hawkbit/src/main/resources/META-INF/services/org.openremote.model.AssetModelProvider +++ b/hawkbit/src/main/resources/META-INF/services/org.openremote.model.AssetModelProvider @@ -1 +1 @@ -org.openremote.extension.hawkbit.model.firmware.FirmwareModelProvider +org.openremote.extension.hawkbit.model.FirmwareModelProvider diff --git a/hawkbit/src/main/resources/META-INF/services/org.openremote.model.ContainerService b/hawkbit/src/main/resources/META-INF/services/org.openremote.model.ContainerService index 5050c88..b99fe38 100644 --- a/hawkbit/src/main/resources/META-INF/services/org.openremote.model.ContainerService +++ b/hawkbit/src/main/resources/META-INF/services/org.openremote.model.ContainerService @@ -1 +1 @@ -org.openremote.extension.hawkbit.manager.firmware.FirmwareService +org.openremote.extension.hawkbit.manager.HawkbitFirmwareService diff --git a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy new file mode 100644 index 0000000..62b06bb --- /dev/null +++ b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy @@ -0,0 +1,215 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.manager + +import jakarta.ws.rs.core.Response +import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitTargetsClient +import org.openremote.extension.hawkbit.model.FirmwareMetaItemType +import org.openremote.extension.hawkbit.model.hawkbit.MetadataUpdateRequest +import org.openremote.extension.hawkbit.model.hawkbit.Target +import org.openremote.model.asset.Asset +import org.openremote.model.asset.AssetEvent +import org.openremote.model.attribute.AttributeEvent +import org.openremote.model.attribute.AttributeMap +import org.openremote.model.attribute.MetaItem +import org.openremote.model.attribute.MetaMap +import org.openremote.model.value.AttributeDescriptor +import org.openremote.test.ManagerContainerTrait +import spock.lang.Specification + +import static org.openremote.model.value.ValueType.TEXT + +class HawkbitFirmwareServiceTest extends Specification implements ManagerContainerTrait { + + private static final String CONTROLLER_ID = "test-asset-id" + + /** + * Subclass that bypasses asset type descriptor lookup so asset sync logic can be tested + * with any asset type. + */ + static class TestableHawkbitFirmwareService extends HawkbitFirmwareService { + protected Optional> getFirmwareTargetInfoDescriptor(Asset asset) { + return Optional.of(new AttributeDescriptor<>("firmwareTarget", TEXT)) + } + } + + def "handleAssetChange with CREATE cause creates target when it does not exist"() { + given: "a service with mocked targets client" + def service = new TestableHawkbitFirmwareService() + service.targets = Mock(HawkbitTargetsClient) + def asset = Mock(Asset) + asset.getId() >> CONTROLLER_ID + asset.getRealm() >> "master" + asset.getAttributes() >> new AttributeMap() + + when: "handling an asset CREATE event" + service.handleAssetChange(new AssetEvent(AssetEvent.Cause.CREATE, asset)) + + then: "hawkBit creates the target and then queries it to update target info" + 1 * service.targets.create(_) >> Response.ok().build() + 1 * service.targets.get(CONTROLLER_ID) >> Response.ok(new Target(CONTROLLER_ID, null, null, "token", null, null, null, null, null, null, null, null, null)).build() + } + + def "handleAssetChange with UPDATE cause skips create when target already exists"() { + given: "a service with mocked targets client returning an existing target" + def service = new TestableHawkbitFirmwareService() + def existingTarget = new Target(CONTROLLER_ID, null, null, "token", null, null, null, null, null, null, null, null, null) + service.targets = Mock(HawkbitTargetsClient) + + def asset = Mock(Asset) + asset.getId() >> CONTROLLER_ID + asset.getRealm() >> "master" + asset.getAttributes() >> new AttributeMap() + + when: "handling an asset UPDATE event" + service.handleAssetChange(new AssetEvent(AssetEvent.Cause.UPDATE, asset)) + + then: "hawkBit is queried but create is not called" + 2 * service.targets.get(CONTROLLER_ID) >> Response.ok(existingTarget).build() + 0 * service.targets.create(_) + } + + def "handleAssetChange with UPDATE cause creates target when it is missing"() { + given: "a service with mocked targets client returning 404 then the created target" + def service = new TestableHawkbitFirmwareService() + service.targets = Mock(HawkbitTargetsClient) + + def asset = Mock(Asset) + asset.getId() >> CONTROLLER_ID + asset.getRealm() >> "master" + asset.getAttributes() >> new AttributeMap() + + when: "handling an asset UPDATE event for a missing target" + service.handleAssetChange(new AssetEvent(AssetEvent.Cause.UPDATE, asset)) + + then: "hawkBit queries (404), creates, then queries again for info update" + 2 * service.targets.get(CONTROLLER_ID) >>> [ + Response.status(Response.Status.NOT_FOUND).build(), + Response.ok(new Target(CONTROLLER_ID, null, null, "token", null, null, null, null, null, null, null, null, null)).build() + ] + 1 * service.targets.create(_) >> Response.ok().build() + } + + def "handleAssetChange with UPDATE cause logs warning when getFirmwareTarget throws exception"() { + given: "a service with mocked targets client that throws" + def service = new TestableHawkbitFirmwareService() + service.targets = Mock(HawkbitTargetsClient) + + def asset = Mock(Asset) + asset.getId() >> CONTROLLER_ID + asset.getRealm() >> "master" + + when: "handling an asset UPDATE event when hawkBit query fails" + service.handleAssetChange(new AssetEvent(AssetEvent.Cause.UPDATE, asset)) + + then: "hawkBit is queried but throws, no create is attempted" + 1 * service.targets.get(CONTROLLER_ID) >> { throw new RuntimeException("connection failed") } + 0 * service.targets.create(_) + 0 * service.targets.delete(_) + } + + def "handleAssetChange with DELETE cause deletes target"() { + given: "a service with mocked targets client" + def service = new TestableHawkbitFirmwareService() + service.targets = Mock(HawkbitTargetsClient) + + def asset = Mock(Asset) + asset.getId() >> CONTROLLER_ID + asset.getRealm() >> "master" + + when: "handling an asset DELETE event" + service.handleAssetChange(new AssetEvent(AssetEvent.Cause.DELETE, asset)) + + then: "the delete endpoint is invoked" + 1 * service.targets.delete(CONTROLLER_ID) >> Response.ok().build() + } + + def "handleAttributeChange returns early when attribute has no firmware metadata"() { + given: "a service with mocked targets client" + def service = new TestableHawkbitFirmwareService() + service.targets = Mock(HawkbitTargetsClient) + + when: "handling an attribute event without firmware metadata" + service.handleAttributeChange(new AttributeEvent(CONTROLLER_ID, "temp", 25)) + + then: "no hawkBit calls are made" + 0 * service.targets.updateMetadata(_, _, _) + 0 * service.targets.deleteMetadata(_, _) + } + + def "handleAttributeChange deletes metadata when attribute event is marked deleted"() { + given: "a service with mocked targets client" + def service = new TestableHawkbitFirmwareService() + service.targets = Mock(HawkbitTargetsClient) { + deleteMetadata(_ as String, _ as String) >> Response.ok().build() + } + def meta = new MetaMap() + meta.put(new MetaItem<>(FirmwareMetaItemType.FIRMWARE_METADATA, true)) + + def event = new AttributeEvent(CONTROLLER_ID, "temp", 25) + event.setMeta(meta) + event.setDeleted(true) + + when: "handling a deleted attribute event with firmware metadata" + service.handleAttributeChange(event) + + then: "deleteMetadata is called and updateMetadata is not" + 1 * service.targets.deleteMetadata(CONTROLLER_ID, "temp") + 0 * service.targets.updateMetadata(_, _, _) + } + + def "handleAttributeChange updates metadata when attribute has firmware metadata"() { + given: "a service with mocked targets client" + def service = new TestableHawkbitFirmwareService() + service.targets = Mock(HawkbitTargetsClient) { + updateMetadata(_ as String, _ as String, _ as MetadataUpdateRequest) >> Response.ok().build() + } + def meta = new MetaMap() + meta.put(new MetaItem<>(FirmwareMetaItemType.FIRMWARE_METADATA, true)) + + def event = new AttributeEvent(CONTROLLER_ID, "temp", 25) + event.setMeta(meta) + + when: "handling an attribute event with a metadata value" + service.handleAttributeChange(event) + + then: "updateMetadata is called with the string coerced value" + 1 * service.targets.updateMetadata(CONTROLLER_ID, "temp", _) + } + + def "handleAttributeChange deletes metadata when attribute value is empty"() { + given: "a service with mocked targets client" + def service = new TestableHawkbitFirmwareService() + service.targets = Mock(HawkbitTargetsClient) { + deleteMetadata(_ as String, _ as String) >> Response.ok().build() + } + def meta = new MetaMap() + meta.put(new MetaItem<>(FirmwareMetaItemType.FIRMWARE_METADATA, true)) + + def event = new AttributeEvent(CONTROLLER_ID, "temp", "") + event.setMeta(meta) + + when: "handling an attribute event with an empty value" + service.handleAttributeChange(event) + + then: "deleteMetadata is called" + 1 * service.targets.deleteMetadata(CONTROLLER_ID, "temp") + } +} diff --git a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitResponseHandlerTest.groovy b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitResponseHandlerTest.groovy new file mode 100644 index 0000000..b6ae0dd --- /dev/null +++ b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitResponseHandlerTest.groovy @@ -0,0 +1,232 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.manager + +import com.fasterxml.jackson.databind.JsonNode +import jakarta.ws.rs.WebApplicationException +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response +import org.openremote.model.util.ValueUtil +import spock.lang.Specification + +class HawkbitResponseHandlerTest extends Specification { + + def "strips HAL fields from single resource response"() { + given: "a hawkBit HAL resource response" + def upstream = jsonResponse(''' + { + "id": 42, + "name": "target-a", + "nested": { + "enabled": true, + "_links": { + "self": {"href": "http://hawkbit/rest/v1/nested/7"} + } + }, + "_links": { + "self": {"href": "http://hawkbit/rest/v1/targets/42"} + }, + "_embedded": { + "ignored": [{"id": 1}] + } + } + ''') + + when: "the response is adapted" + def formatted = HawkbitResponseHandler.call("Failed to call hawkBit", { upstream }) + def body = readJson(formatted) + + then: "HAL fields are removed and normal fields are preserved" + formatted.status == 200 + formatted.mediaType == MediaType.APPLICATION_JSON_TYPE + body.path("id").asInt() == 42 + body.path("name").asText() == "target-a" + body.path("nested").path("enabled").asBoolean() + !body.has("_links") + !body.has("_embedded") + !body.path("nested").has("_links") + } + + def "maps distribution set link to explicit fields"() { + given: "a hawkBit resource response with a distribution set link" + def upstream = jsonResponse(''' + { + "id": 7, + "_links": { + "distributionset": { + "href": "http://hawkbit/rest/v1/distributionsets/123", + "name": "Release 1.2.3" + } + } + } + ''') + + when: "the response is adapted" + def body = readJson(HawkbitResponseHandler.call("Failed to call hawkBit", { upstream })) + + then: "the link is represented as explicit fields" + body.path("id").asInt() == 7 + body.path("distributionSetId").asLong() == 123L + body.path("distributionSetName").asText() == "Release 1.2.3" + !body.has("_links") + } + + def "flattens embedded HAL collection to paged response"() { + given: "a hawkBit HAL collection response" + def upstream = jsonResponse(''' + { + "_embedded": { + "targets": [ + {"controllerId": "target-a", "_links": {"self": {"href": "http://hawkbit/rest/v1/targets/target-a"}}}, + {"controllerId": "target-b", "_embedded": {"ignored": []}} + ] + }, + "page": { + "totalElements": 10, + "size": 2 + } + } + ''') + + when: "the response is adapted" + def body = readJson(HawkbitResponseHandler.call("Failed to call hawkBit", { upstream })) + + then: "embedded items become page content and HAL fields are stripped" + body.path("total").asInt() == 10 + body.path("size").asInt() == 2 + body.path("content").size() == 2 + body.path("content").get(0).path("controllerId").asText() == "target-a" + body.path("content").get(1).path("controllerId").asText() == "target-b" + !body.path("content").get(0).has("_links") + !body.path("content").get(1).has("_embedded") + } + + def "flattens root array to paged response"() { + given: "a JSON array response" + def upstream = jsonResponse(''' + [ + {"id": 1, "_links": {"self": {"href": "http://hawkbit/rest/v1/items/1"}}}, + {"id": 2} + ] + ''') + + when: "the response is adapted" + def body = readJson(HawkbitResponseHandler.call("Failed to call hawkBit", { upstream })) + + then: "array items become page content" + body.path("total").asInt() == 2 + body.path("size").asInt() == 2 + body.path("content").size() == 2 + body.path("content").get(0).path("id").asInt() == 1 + body.path("content").get(1).path("id").asInt() == 2 + !body.path("content").get(0).has("_links") + } + + def "flattens content array to paged response"() { + given: "a Spring Data REST paged response" + def upstream = jsonResponse(''' + { + "content": [ + {"id": 3, "_links": {"self": {"href": "http://hawkbit/rest/v1/items/3"}}}, + {"id": 4} + ], + "page": { + "totalElements": 5, + "size": 2 + } + } + ''') + + when: "the response is adapted" + def body = readJson(HawkbitResponseHandler.call("Failed to call hawkBit", { upstream })) + + then: "content items are preserved and HAL fields are stripped" + body.path("total").asInt() == 5 + body.path("size").asInt() == 2 + body.path("content").size() == 2 + body.path("content").get(0).path("id").asInt() == 3 + body.path("content").get(1).path("id").asInt() == 4 + !body.path("content").get(0).has("_links") + } + + def "preserves non-JSON body and media type"() { + given: "an upstream response with a non-JSON body" + def upstream = Response.status(Response.Status.BAD_GATEWAY) + .type(MediaType.TEXT_PLAIN_TYPE) + .entity("upstream unavailable") + .build() + + when: "the response is adapted" + def formatted = HawkbitResponseHandler.call("Failed to call hawkBit", { upstream }) + + then: "the original body and media type are preserved" + formatted.status == Response.Status.BAD_GATEWAY.statusCode + formatted.mediaType == MediaType.TEXT_PLAIN_TYPE + formatted.readEntity(String) == "upstream unavailable" + } + + def "returns empty response when no entity"() { + given: "an upstream response without an entity" + def upstream = Response.noContent().build() + + when: "the response is adapted" + def formatted = HawkbitResponseHandler.call("Failed to call hawkBit", { upstream }) + + then: "the empty status is preserved" + formatted.status == Response.Status.NO_CONTENT.statusCode + !formatted.hasEntity() + } + + def "wraps checked exceptions as bad gateway"() { + when: "an adapted call throws an unexpected exception" + HawkbitResponseHandler.call("Failed to call hawkBit", { + throw new IOException("connection failed") + }) + + then: "the exception is wrapped as a bad gateway response" + def e = thrown(WebApplicationException) + e.response.status == Response.Status.BAD_GATEWAY.statusCode + e.message == "Failed to call hawkBit" + e.cause instanceof IOException + } + + def "rethrows web application exceptions unchanged"() { + given: "an existing web application exception" + def original = new WebApplicationException("not found", Response.Status.NOT_FOUND) + + when: "an adapted call throws it" + HawkbitResponseHandler.call("Failed to call hawkBit", { + throw original + }) + + then: "the original exception is rethrown" + def e = thrown(WebApplicationException) + e.is(original) + e.response.status == Response.Status.NOT_FOUND.statusCode + } + + private static Response jsonResponse(String body) { + Response.ok(body, MediaType.APPLICATION_JSON_TYPE).build() + } + + private static JsonNode readJson(Response response) { + ValueUtil.JSON.readTree(response.readEntity(String)) + } +} From 278609d9c19b9c81fc4f608445fad30e90a85127 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Fri, 15 May 2026 12:14:13 +0200 Subject: [PATCH 10/18] Update README.md --- hawkbit/README.md | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/hawkbit/README.md b/hawkbit/README.md index 875eb10..3c52d44 100644 --- a/hawkbit/README.md +++ b/hawkbit/README.md @@ -174,21 +174,39 @@ sequenceDiagram ## Components ``` -manager/firmware/ - FirmwareService.java Starts the integration, syncs assets and registers API resources - FirmwareTargetResourceImpl.java Proxies target and action requests to hawkBit - FirmwareSoftwareModuleResourceImpl.java Proxies software module requests and artifact uploads - FirmwareDistributionSetResourceImpl.java Proxies distribution set requests and target assignment - FirmwareRolloutResourceImpl.java Proxies rollout requests +manager/ + HawkbitFirmwareService.java Starts the integration, syncs assets and registers API resources + HawkbitResponseHandler.java Calls hawkBit clients and adapts responses for OpenRemote APIs + +manager/resource/ + TargetResourceImpl.java Proxies target and action requests to hawkBit + SoftwareModuleResourceImpl.java Proxies software module requests and artifact uploads + DistributionSetResourceImpl.java Proxies distribution set requests and target assignment + DistributionSetTypeResourceImpl.java Proxies distribution set type requests + SoftwareModuleTypeResourceImpl.java Proxies software module type requests + TargetFilterResourceImpl.java Proxies target filter requests + RolloutResourceImpl.java Proxies rollout requests manager/hawkbit/ - HawkbitTargetsResource.java RESTEasy client proxy for hawkBit targets - HawkbitSoftwareModulesResource.java RESTEasy client proxy for software modules - HawkbitDistributionSetsResource.java RESTEasy client proxy for distribution sets - HawkbitRolloutsResource.java RESTEasy client proxy for rollouts - HawkbitArtifactUploadClient.java Multipart artifact upload client - -model/firmware/ + HawkbitTargetsClient.java RESTEasy client proxy for hawkBit targets + HawkbitSoftwareModulesClient.java RESTEasy client proxy for software modules + HawkbitDistributionSetsClient.java RESTEasy client proxy for distribution sets + HawkbitDistributionSetTypesClient.java RESTEasy client proxy for distribution set types + HawkbitSoftwareModuleTypesClient.java RESTEasy client proxy for software module types + HawkbitTargetFiltersClient.java RESTEasy client proxy for target filters + HawkbitRolloutsClient.java RESTEasy client proxy for rollouts + HawkbitBasicAuth.java Builds hawkBit basic auth headers + HawkbitMediaType.java Defines hawkBit media types + +model/ FirmwareMetaItemType.java Defines firmwareTarget and firmwareMetadata meta items FirmwareModelProvider.java Registers firmware meta items in the OpenRemote model + +model/resource/ + TargetResource.java Defines OpenRemote firmware target endpoints + SoftwareModuleResource.java Defines OpenRemote firmware software module endpoints + DistributionSetResource.java Defines OpenRemote firmware distribution set endpoints + +model/hawkbit/ + hawkBit API payload records used by the RESTEasy clients and firmware resources ``` From dc0094a0e07ae1ed583b3dad145053111efa748b Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Fri, 15 May 2026 17:37:09 +0200 Subject: [PATCH 11/18] Refactor more into the proxy model --- hawkbit/README.md | 2 +- .../manager/HawkbitFirmwareService.java | 2 +- .../manager/HawkbitResponseHandler.java | 225 ------------------ .../hawkbit/manager/HawkbitResponseProxy.java | 71 ++++++ .../HawkbitDistributionSetTypesClient.java | 4 +- .../HawkbitDistributionSetsClient.java | 9 +- .../hawkbit/HawkbitRolloutsClient.java | 4 +- .../HawkbitSoftwareModuleTypesClient.java | 4 +- .../hawkbit/HawkbitSoftwareModulesClient.java | 4 +- .../hawkbit/HawkbitTargetFiltersClient.java | 7 +- .../resource/DistributionSetResourceImpl.java | 26 +- .../DistributionSetTypeResourceImpl.java | 21 +- .../manager/resource/RolloutResourceImpl.java | 22 +- .../resource/SoftwareModuleResourceImpl.java | 19 +- .../SoftwareModuleTypeResourceImpl.java | 17 +- .../resource/TargetFilterResourceImpl.java | 23 +- .../manager/resource/TargetResourceImpl.java | 18 +- .../AutoAssignDistributionSetRequest.java | 30 --- .../DistributionSetAssignmentRequest.java | 31 --- .../hawkbit/DistributionSetCreateRequest.java | 31 --- .../DistributionSetTypeCreateRequest.java | 31 --- .../model/hawkbit/RolloutActionRequest.java | 26 -- .../hawkbit/RolloutConditionRequest.java | 26 -- .../model/hawkbit/RolloutCreateRequest.java | 40 ---- .../hawkbit/SoftwareModuleCreateRequest.java | 32 --- .../SoftwareModuleReferenceRequest.java | 26 -- .../SoftwareModuleTypeCreateRequest.java | 30 --- .../hawkbit/TargetFilterCreateRequest.java | 26 -- .../resource/DistributionSetResource.java | 7 +- .../resource/DistributionSetTypeResource.java | 4 +- .../model/resource/RolloutResource.java | 4 +- .../resource/SoftwareModuleResource.java | 4 +- .../resource/SoftwareModuleTypeResource.java | 4 +- .../model/resource/TargetFilterResource.java | 7 +- ...groovy => HawkbitResponseProxyTest.groovy} | 124 ++-------- 35 files changed, 197 insertions(+), 764 deletions(-) delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseHandler.java create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseProxy.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/AutoAssignDistributionSetRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetAssignmentRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetCreateRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetTypeCreateRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutActionRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutConditionRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutCreateRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleCreateRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleReferenceRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleTypeCreateRequest.java delete mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetFilterCreateRequest.java rename hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/{HawkbitResponseHandlerTest.groovy => HawkbitResponseProxyTest.groovy} (51%) diff --git a/hawkbit/README.md b/hawkbit/README.md index 3c52d44..f8e560d 100644 --- a/hawkbit/README.md +++ b/hawkbit/README.md @@ -176,7 +176,7 @@ sequenceDiagram ``` manager/ HawkbitFirmwareService.java Starts the integration, syncs assets and registers API resources - HawkbitResponseHandler.java Calls hawkBit clients and adapts responses for OpenRemote APIs + HawkbitResponseProxy.java Proxies hawkBit client responses for OpenRemote APIs manager/resource/ TargetResourceImpl.java Proxies target and action requests to hawkBit diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java index 2822445..ba8e39b 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java @@ -515,7 +515,7 @@ public Response uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream String uploadFilename = TextUtil.isNullOrEmpty(effectiveFilename) ? "artifact.bin" : effectiveFilename; MultipartFormDataOutput form = new MultipartFormDataOutput(); form.addFormData("file", inputStream, MediaType.APPLICATION_OCTET_STREAM_TYPE, uploadFilename); - return HawkbitResponseHandler.call("Failed to upload artifact for firmware software module '" + softwareModuleId + "'", + return HawkbitResponseProxy.proxy("Failed to upload artifact for firmware software module '" + softwareModuleId + "'", () -> softwareModules.uploadArtifact(softwareModuleId, TextUtil.isNullOrEmpty(effectiveFilename) ? null : effectiveFilename, form)); diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseHandler.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseHandler.java deleted file mode 100644 index e75b7ad..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseHandler.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.manager; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.openremote.model.util.ValueUtil; - -import java.util.Map; - -public final class HawkbitResponseHandler { - - private static final Map HAL_LINK_FIELDS = Map.of( - "distributionset", new LinkFieldMapping("distributionSetId", "distributionSetName")); - - private HawkbitResponseHandler() { - } - - /** - * Executes a hawkBit call, adapts the response (strips HAL, flattens collections), - * and wraps any unexpected failure as {@code BAD_GATEWAY}. - *

- * The upstream {@link Response} is consumed and closed by this call. - */ - public static Response call(String errorMessage, HawkbitCall call) { - try { - return adaptHawkbitResponse(call.execute()); - } catch (WebApplicationException e) { - throw e; - } catch (Exception e) { - throw new WebApplicationException(errorMessage, e, Response.Status.BAD_GATEWAY); - } - } - - /** - * Consumes the upstream response and builds a new one with HAL fields removed. - * Preserves non-JSON bodies and empty responses unchanged. - */ - protected static Response adaptHawkbitResponse(Response response) { - try (response) { - Response.ResponseBuilder builder = Response.status(response.getStatus()); - if (!response.hasEntity()) { - return builder.build(); - } - - String body = response.readEntity(String.class); - if (body.isBlank()) { - return builder.build(); - } - - try { - JsonNode root = ValueUtil.JSON.readTree(body); - JsonNode formatted = isCollectionResponse(root) ? toFlatPage(root) : cleanHalFields(root); - return builder - .type(MediaType.APPLICATION_JSON_TYPE) - .entity(ValueUtil.JSON.writeValueAsString(formatted)) - .build(); - } catch (Exception ignored) { - MediaType mediaType = response.getMediaType() == null - ? MediaType.TEXT_PLAIN_TYPE - : response.getMediaType(); - return builder.type(mediaType).entity(body).build(); - } - } catch (Exception e) { - throw new WebApplicationException("Failed to adapt hawkBit response", e, - Response.Status.BAD_GATEWAY); - } - } - - /** - * Detects collection responses (arrays, paged objects, or HAL {@code _embedded} arrays). - * Single resources with {@code _embedded} relations are excluded by checking for - * typical identifier fields such as {@code id} or {@code controllerId}. - */ - protected static boolean isCollectionResponse(JsonNode root) { - if (root.isArray()) { - return true; - } - if (root.path("content").isArray()) { - return true; - } - JsonNode embedded = root.path("_embedded"); - if (embedded.isObject() && !firstArrayItems(embedded).isEmpty()) { - // Single HAL resources may contain _embedded relations; only treat as collection - // if the root lacks typical single-resource identifier fields. - return !root.has("id") && !root.has("controllerId"); - } - return false; - } - - protected static ObjectNode toFlatPage(JsonNode root) { - ArrayNode content = JsonNodeFactory.instance.arrayNode(); - if (root.isArray()) { - root.forEach(item -> content.add(cleanHalFields(item))); - } else if (root.has("_embedded")) { - firstArrayItems(root.get("_embedded")).forEach(item -> content.add(cleanHalFields(item))); - } else if (root.path("content").isArray()) { - root.get("content").forEach(item -> content.add(cleanHalFields(item))); - } - - ObjectNode formatted = JsonNodeFactory.instance.objectNode(); - formatted.set("content", content); - formatted.put("total", intFieldOrDefault(root, "total", - intFieldOrDefault(root.path("page"), "totalElements", content.size()))); - formatted.put("size", intFieldOrDefault(root, "size", - intFieldOrDefault(root.path("page"), "size", content.size()))); - return formatted; - } - - /** - * Recursively removes {@code _links} and {@code _embedded} from HAL JSON, - * copying any mapped links to explicit fields (e.g. {@code distributionSetId}). - */ - protected static JsonNode cleanHalFields(JsonNode node) { - return switch (node) { - case ArrayNode array -> { - ArrayNode formatted = JsonNodeFactory.instance.arrayNode(); - array.forEach(item -> formatted.add(cleanHalFields(item))); - yield formatted; - } - case ObjectNode object -> { - ObjectNode formatted = JsonNodeFactory.instance.objectNode(); - for (Map.Entry field : object.properties()) { - if ("_links".equals(field.getKey()) || "_embedded".equals(field.getKey())) { - continue; - } - formatted.set(field.getKey(), cleanHalFields(field.getValue())); - } - copyMappedHalLinkFields(object.path("_links"), formatted); - yield formatted; - } - default -> node; - }; - } - - protected static void copyMappedHalLinkFields(JsonNode links, ObjectNode target) { - if (!links.isObject()) { - return; - } - - HAL_LINK_FIELDS.forEach((rel, mapping) -> { - JsonNode link = links.path(rel); - Long id = extractIdFromHref(link.path("href")); - if (id != null && !target.has(mapping.idField())) { - target.put(mapping.idField(), id); - } - JsonNode name = link.path("name"); - if (name.isTextual() && !target.has(mapping.nameField())) { - target.put(mapping.nameField(), name.textValue()); - } - }); - } - - protected static Long extractIdFromHref(JsonNode hrefNode) { - if (!hrefNode.isTextual()) { - return null; - } - - String href = hrefNode.textValue(); - int end = href.endsWith("/") ? href.length() - 1 : href.length(); - int start = href.lastIndexOf('/', end - 1) + 1; - if (start >= end) { - return null; - } - try { - return Long.parseLong(href.substring(start, end)); - } catch (NumberFormatException ignored) { - return null; - } - } - - protected static ArrayNode firstArrayItems(JsonNode embedded) { - ArrayNode content = JsonNodeFactory.instance.arrayNode(); - if (!embedded.isObject()) { - return content; - } - - for (JsonNode value : embedded) { - if (value.isArray()) { - value.forEach(content::add); - return content; - } - } - return content; - } - - protected static int intFieldOrDefault(JsonNode node, String field, int defaultValue) { - JsonNode value = node.path(field); - return value.isNumber() ? value.intValue() : defaultValue; - } - - /** - * Replaces {@link java.util.function.Supplier} to allow checked exceptions - * to propagate without {@code UndeclaredThrowableException} wrapping. - */ - @FunctionalInterface - public interface HawkbitCall { - Response execute() throws Exception; - } - - protected record LinkFieldMapping(String idField, String nameField) { - } -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseProxy.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseProxy.java new file mode 100644 index 0000000..7c9edf7 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitResponseProxy.java @@ -0,0 +1,71 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.manager; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; + +public final class HawkbitResponseProxy { + + private HawkbitResponseProxy() { + } + + /** + * Executes a hawkBit call and wraps any unexpected failure as {@code BAD_GATEWAY}. + *

+ * The upstream {@link Response} is copied, consumed, and closed by this call. + */ + public static Response proxy(String errorMessage, HawkbitCall call) { + try { + return copyResponse(call.execute()); + } catch (WebApplicationException e) { + throw e; + } catch (Exception e) { + throw new WebApplicationException(errorMessage, e, Response.Status.BAD_GATEWAY); + } + } + + private static Response copyResponse(Response response) { + try (response) { + Response.ResponseBuilder builder = Response.fromResponse(response); + if (!response.hasEntity()) { + return builder.build(); + } + + String body = response.readEntity(String.class); + if (body.isBlank()) { + return builder.entity(null).build(); + } + return builder.entity(body).build(); + } catch (Exception e) { + throw new WebApplicationException("Failed to copy hawkBit response", e, + Response.Status.BAD_GATEWAY); + } + } + + /** + * Replaces {@link java.util.function.Supplier} to allow checked exceptions + * to propagate without {@code UndeclaredThrowableException} wrapping. + */ + @FunctionalInterface + public interface HawkbitCall { + Response execute() throws Exception; + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesClient.java index 703281a..fdb3282 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetTypesClient.java @@ -19,9 +19,9 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetTypeCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @@ -32,7 +32,7 @@ public interface HawkbitDistributionSetTypesClient { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(DistributionSetTypeCreateRequest[] distributionSetTypes); + Response create(JsonNode distributionSetTypes); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsClient.java index 3f44a14..ab0c638 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsClient.java @@ -19,10 +19,9 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetAssignmentRequest; -import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @@ -33,15 +32,15 @@ public interface HawkbitDistributionSetsClient { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(DistributionSetCreateRequest[] distributionSets); + Response create(JsonNode distributionSets); @POST @Path("{id}/assignedTargets") @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) Response assignTargets(@PathParam("id") Long id, - @QueryParam("offline") Boolean offline, - DistributionSetAssignmentRequest[] targets); + @QueryParam("offline") Boolean offline, + JsonNode targets); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsClient.java index 1ca6d5c..dca2503 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsClient.java @@ -19,9 +19,9 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.hawkbit.RolloutCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @@ -43,7 +43,7 @@ Response getRollouts(@QueryParam("offset") Integer offset, @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(RolloutCreateRequest rollout); + Response create(JsonNode rollout); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesClient.java index d7aba49..fd94fba 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModuleTypesClient.java @@ -19,9 +19,9 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleTypeCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @@ -32,7 +32,7 @@ public interface HawkbitSoftwareModuleTypesClient { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(SoftwareModuleTypeCreateRequest[] softwareModuleTypes); + Response create(JsonNode softwareModuleTypes); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesClient.java index 4ee71e7..2b8cbc7 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitSoftwareModulesClient.java @@ -19,10 +19,10 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; -import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static jakarta.ws.rs.core.MediaType.MULTIPART_FORM_DATA; @@ -34,7 +34,7 @@ public interface HawkbitSoftwareModulesClient { @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(SoftwareModuleCreateRequest[] softwareModules); + Response create(JsonNode softwareModules); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersClient.java index 9de81aa..edebdf3 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetFiltersClient.java @@ -19,10 +19,9 @@ */ package org.openremote.extension.hawkbit.manager.hawkbit; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.hawkbit.AutoAssignDistributionSetRequest; -import org.openremote.extension.hawkbit.model.hawkbit.TargetFilterCreateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @@ -43,7 +42,7 @@ Response getTargetFilters(@QueryParam("offset") Integer offset, @POST @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) - Response create(TargetFilterCreateRequest filter); + Response create(JsonNode filter); @DELETE @Path("{filterId}") @@ -59,7 +58,7 @@ Response getTargetFilters(@QueryParam("offset") Integer offset, @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) Response setAutoAssignDS(@PathParam("filterId") Long filterId, - AutoAssignDistributionSetRequest request); + JsonNode request); @DELETE @Path("{filterId}/autoAssignDS") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java index af85694..5d8726c 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java @@ -19,13 +19,12 @@ */ package org.openremote.extension.hawkbit.manager.resource; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; -import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; -import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetAssignmentRequest; -import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetCreateRequest; +import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.DistributionSetResource; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; @@ -44,38 +43,37 @@ public DistributionSetResourceImpl(TimerService timerService, ManagerIdentitySer @Override public Response createDistributionSet(RequestParams requestParams, - DistributionSetCreateRequest distributionSet) { - return HawkbitResponseHandler.call("Failed to create firmware distribution set", - () -> hawkbitFirmwareService.distributionSets().create( - new DistributionSetCreateRequest[]{distributionSet})); + JsonNode distributionSet) { + return HawkbitResponseProxy.proxy("Failed to create firmware distribution set", + () -> hawkbitFirmwareService.distributionSets().create(distributionSet)); } @Override public Response assignDistributionSet(RequestParams requestParams, Long id, - Boolean offline, - DistributionSetAssignmentRequest[] targets) { - if (targets == null || targets.length == 0) { + Boolean offline, + JsonNode targets) { + if (targets == null || !targets.isArray() || targets.isEmpty()) { throw new WebApplicationException("Assignment requires at least one target", Response.Status.BAD_REQUEST); } - return HawkbitResponseHandler.call("Failed to assign firmware distribution set '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to assign firmware distribution set '" + id + "'", () -> hawkbitFirmwareService.distributionSets().assignTargets(id, offline, targets)); } @Override public Response getDistributionSets(RequestParams requestParams, Integer offset, Integer limit) { - return HawkbitResponseHandler.call("Failed to retrieve firmware distribution sets", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware distribution sets", () -> hawkbitFirmwareService.distributionSets().getDistributionSets(offset, limit)); } @Override public Response getDistributionSet(RequestParams requestParams, Long id) { - return HawkbitResponseHandler.call("Failed to retrieve firmware distribution set '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware distribution set '" + id + "'", () -> hawkbitFirmwareService.distributionSets().get(id)); } @Override public void deleteDistributionSet(RequestParams requestParams, Long id) { - HawkbitResponseHandler.call("Failed to delete firmware distribution set '" + id + "'", + HawkbitResponseProxy.proxy("Failed to delete firmware distribution set '" + id + "'", () -> hawkbitFirmwareService.distributionSets().delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java index cd21894..fe22bfe 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java @@ -20,10 +20,10 @@ package org.openremote.extension.hawkbit.manager.resource; import jakarta.ws.rs.core.Response; +import com.fasterxml.jackson.databind.JsonNode; import org.openremote.container.timer.TimerService; import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; -import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; -import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetTypeCreateRequest; +import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.DistributionSetTypeResource; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; @@ -43,29 +43,28 @@ public DistributionSetTypeResourceImpl(TimerService timerService, @Override public Response createDistributionSetType(RequestParams requestParams, - DistributionSetTypeCreateRequest distributionSetType) { - return HawkbitResponseHandler.call("Failed to create firmware distribution set type", - () -> hawkbitFirmwareService.distributionSetTypes().create( - new DistributionSetTypeCreateRequest[]{distributionSetType})); + JsonNode distributionSetType) { + return HawkbitResponseProxy.proxy("Failed to create firmware distribution set type", + () -> hawkbitFirmwareService.distributionSetTypes().create(distributionSetType)); } @Override public Response getDistributionSetTypes(RequestParams requestParams, Integer offset, Integer limit) { - return HawkbitResponseHandler.call("Failed to retrieve firmware distribution set types", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware distribution set types", () -> hawkbitFirmwareService.distributionSetTypes().getDistributionSetTypes(offset, limit)); } @Override public Response getDistributionSetType(RequestParams requestParams, Long id) { - return HawkbitResponseHandler.call("Failed to retrieve firmware distribution set type '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware distribution set type '" + id + "'", () -> hawkbitFirmwareService.distributionSetTypes().get(id)); } @Override public Response getMandatoryModuleTypes(RequestParams requestParams, Long id, Integer offset, Integer limit) { - return HawkbitResponseHandler.call( + return HawkbitResponseProxy.proxy( "Failed to retrieve mandatory module types for firmware distribution set type '" + id + "'", () -> hawkbitFirmwareService.distributionSetTypes().getMandatoryModuleTypes(id, offset, limit)); } @@ -73,14 +72,14 @@ public Response getMandatoryModuleTypes(RequestParams requestParams, Long id, In @Override public Response getOptionalModuleTypes(RequestParams requestParams, Long id, Integer offset, Integer limit) { - return HawkbitResponseHandler.call( + return HawkbitResponseProxy.proxy( "Failed to retrieve optional module types for firmware distribution set type '" + id + "'", () -> hawkbitFirmwareService.distributionSetTypes().getOptionalModuleTypes(id, offset, limit)); } @Override public void deleteDistributionSetType(RequestParams requestParams, Long id) { - HawkbitResponseHandler.call("Failed to delete firmware distribution set type '" + id + "'", + HawkbitResponseProxy.proxy("Failed to delete firmware distribution set type '" + id + "'", () -> hawkbitFirmwareService.distributionSetTypes().delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java index 7c62865..58ab455 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java @@ -20,10 +20,10 @@ package org.openremote.extension.hawkbit.manager.resource; import jakarta.ws.rs.core.Response; +import com.fasterxml.jackson.databind.JsonNode; import org.openremote.container.timer.TimerService; import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; -import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; -import org.openremote.extension.hawkbit.model.hawkbit.RolloutCreateRequest; +import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.RolloutResource; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; @@ -43,50 +43,50 @@ public RolloutResourceImpl(TimerService timerService, ManagerIdentityService ide @Override public Response getRollouts(RequestParams requestParams, Integer offset, Integer limit) { // Request full representation so totalTargetsPerStatus and totalGroups are populated; hawkBit defaults to compact. - return HawkbitResponseHandler.call("Failed to retrieve firmware rollouts", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware rollouts", () -> hawkbitFirmwareService.rollouts().getRollouts(offset, limit, "full")); } @Override public Response getRollout(RequestParams requestParams, Long id) { - return HawkbitResponseHandler.call("Failed to retrieve firmware rollout '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().get(id)); } @Override - public Response createRollout(RequestParams requestParams, RolloutCreateRequest rollout) { - return HawkbitResponseHandler.call("Failed to create firmware rollout", + public Response createRollout(RequestParams requestParams, JsonNode rollout) { + return HawkbitResponseProxy.proxy("Failed to create firmware rollout", () -> hawkbitFirmwareService.rollouts().create(rollout)); } @Override public void deleteRollout(RequestParams requestParams, Long id) { - HawkbitResponseHandler.call("Failed to delete firmware rollout '" + id + "'", + HawkbitResponseProxy.proxy("Failed to delete firmware rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().delete(id)); } @Override public Response startRollout(RequestParams requestParams, Long id) { - return HawkbitResponseHandler.call("Failed to start firmware rollout '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to start firmware rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().start(id)); } @Override public void pauseRollout(RequestParams requestParams, Long id) { - HawkbitResponseHandler.call("Failed to pause firmware rollout '" + id + "'", + HawkbitResponseProxy.proxy("Failed to pause firmware rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().pause(id)); } @Override public Response getRolloutGroups(RequestParams requestParams, Long id, Integer offset, Integer limit) { - return HawkbitResponseHandler.call("Failed to retrieve groups for rollout '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve groups for rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().getRolloutGroups(id, offset, limit, "full")); } @Override public Response getRolloutGroup(RequestParams requestParams, Long id, Long groupId) { - return HawkbitResponseHandler.call( + return HawkbitResponseProxy.proxy( "Failed to retrieve group '" + groupId + "' for rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().getRolloutGroup(id, groupId)); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java index 9385794..96920c9 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java @@ -19,13 +19,13 @@ */ package org.openremote.extension.hawkbit.manager.resource; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.EntityPart; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; -import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; -import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleCreateRequest; +import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.SoftwareModuleResource; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; @@ -47,27 +47,26 @@ public SoftwareModuleResourceImpl(TimerService timerService, ManagerIdentityServ @Override public Response createSoftwareModule(RequestParams requestParams, - SoftwareModuleCreateRequest softwareModule) { - return HawkbitResponseHandler.call("Failed to create firmware software module", - () -> hawkbitFirmwareService.softwareModules().create( - new SoftwareModuleCreateRequest[]{softwareModule})); + JsonNode softwareModule) { + return HawkbitResponseProxy.proxy("Failed to create firmware software module", + () -> hawkbitFirmwareService.softwareModules().create(softwareModule)); } @Override public Response getSoftwareModules(RequestParams requestParams, Integer offset, Integer limit) { - return HawkbitResponseHandler.call("Failed to retrieve firmware software modules", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware software modules", () -> hawkbitFirmwareService.softwareModules().getSoftwareModules(offset, limit)); } @Override public Response getSoftwareModule(RequestParams requestParams, Long id) { - return HawkbitResponseHandler.call("Failed to retrieve firmware software module '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware software module '" + id + "'", () -> hawkbitFirmwareService.softwareModules().get(id)); } @Override public Response getSoftwareModuleArtifacts(RequestParams requestParams, Long id) { - return HawkbitResponseHandler.call("Failed to retrieve artifacts for firmware software module '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve artifacts for firmware software module '" + id + "'", () -> hawkbitFirmwareService.softwareModules().getArtifacts(id)); } @@ -98,7 +97,7 @@ public Response uploadSoftwareModuleArtifact(RequestParams requestParams, @Override public void deleteSoftwareModule(RequestParams requestParams, Long id) { - HawkbitResponseHandler.call("Failed to delete firmware software module '" + id + "'", + HawkbitResponseProxy.proxy("Failed to delete firmware software module '" + id + "'", () -> hawkbitFirmwareService.softwareModules().delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java index 734e1e4..0b11054 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java @@ -20,10 +20,10 @@ package org.openremote.extension.hawkbit.manager.resource; import jakarta.ws.rs.core.Response; +import com.fasterxml.jackson.databind.JsonNode; import org.openremote.container.timer.TimerService; import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; -import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; -import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleTypeCreateRequest; +import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.SoftwareModuleTypeResource; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; @@ -42,28 +42,27 @@ public SoftwareModuleTypeResourceImpl(TimerService timerService, ManagerIdentity @Override public Response createSoftwareModuleType(RequestParams requestParams, - SoftwareModuleTypeCreateRequest softwareModuleType) { - return HawkbitResponseHandler.call("Failed to create firmware software module type", - () -> hawkbitFirmwareService.softwareModuleTypes().create( - new SoftwareModuleTypeCreateRequest[]{softwareModuleType})); + JsonNode softwareModuleType) { + return HawkbitResponseProxy.proxy("Failed to create firmware software module type", + () -> hawkbitFirmwareService.softwareModuleTypes().create(softwareModuleType)); } @Override public Response getSoftwareModuleTypes(RequestParams requestParams, Integer offset, Integer limit) { - return HawkbitResponseHandler.call("Failed to retrieve firmware software module types", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware software module types", () -> hawkbitFirmwareService.softwareModuleTypes().getSoftwareModuleTypes(offset, limit)); } @Override public Response getSoftwareModuleType(RequestParams requestParams, Long id) { - return HawkbitResponseHandler.call("Failed to retrieve firmware software module type '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware software module type '" + id + "'", () -> hawkbitFirmwareService.softwareModuleTypes().get(id)); } @Override public void deleteSoftwareModuleType(RequestParams requestParams, Long id) { - HawkbitResponseHandler.call("Failed to delete firmware software module type '" + id + "'", + HawkbitResponseProxy.proxy("Failed to delete firmware software module type '" + id + "'", () -> hawkbitFirmwareService.softwareModuleTypes().delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java index cd6922f..e30fa23 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java @@ -19,12 +19,11 @@ */ package org.openremote.extension.hawkbit.manager.resource; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; -import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; -import org.openremote.extension.hawkbit.model.hawkbit.AutoAssignDistributionSetRequest; -import org.openremote.extension.hawkbit.model.hawkbit.TargetFilterCreateRequest; +import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.TargetFilterResource; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; @@ -43,47 +42,47 @@ public TargetFilterResourceImpl(TimerService timerService, ManagerIdentityServic @Override public Response getTargetFilters(RequestParams requestParams, Integer offset, Integer limit) { - return HawkbitResponseHandler.call("Failed to retrieve firmware target filters", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware target filters", () -> hawkbitFirmwareService.targetFilters().getTargetFilters(offset, limit)); } @Override public Response getTargetFilter(RequestParams requestParams, Long id) { - return HawkbitResponseHandler.call("Failed to retrieve firmware target filter '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware target filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().get(id)); } @Override public Response createTargetFilter(RequestParams requestParams, - TargetFilterCreateRequest filter) { - return HawkbitResponseHandler.call("Failed to create firmware target filter", + JsonNode filter) { + return HawkbitResponseProxy.proxy("Failed to create firmware target filter", () -> hawkbitFirmwareService.targetFilters().create(filter)); } @Override public void deleteTargetFilter(RequestParams requestParams, Long id) { - HawkbitResponseHandler.call("Failed to delete firmware target filter '" + id + "'", + HawkbitResponseProxy.proxy("Failed to delete firmware target filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().delete(id)); } @Override public Response getAutoAssignDS(RequestParams requestParams, Long id) { - return HawkbitResponseHandler.call( + return HawkbitResponseProxy.proxy( "Failed to retrieve auto assign distribution set for filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().getAutoAssignDS(id)); } @Override public Response setAutoAssignDS(RequestParams requestParams, Long id, - AutoAssignDistributionSetRequest request) { - return HawkbitResponseHandler.call( + JsonNode request) { + return HawkbitResponseProxy.proxy( "Failed to set auto assign distribution set for filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().setAutoAssignDS(id, request)); } @Override public void deleteAutoAssignDS(RequestParams requestParams, Long id) { - HawkbitResponseHandler.call( + HawkbitResponseProxy.proxy( "Failed to remove auto assign distribution set from filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().deleteAutoAssignDS(id)); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java index 74a3d79..ec66f6c 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java @@ -22,7 +22,7 @@ import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; -import org.openremote.extension.hawkbit.manager.HawkbitResponseHandler; +import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.TargetResource; import org.openremote.manager.security.ManagerIdentityService; import org.openremote.manager.web.ManagerWebResource; @@ -40,50 +40,50 @@ public TargetResourceImpl(TimerService timerService, ManagerIdentityService iden @Override public Response getTargets(RequestParams requestParams, String query, Integer offset, Integer limit) { - return HawkbitResponseHandler.call("Failed to retrieve firmware targets", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware targets", () -> hawkbitFirmwareService.targets().getTargets(query, offset, limit)); } @Override public Response getTarget(RequestParams requestParams, String id) { - return HawkbitResponseHandler.call("Failed to retrieve firmware target '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().get(id)); } @Override public Response getMetadata(RequestParams requestParams, String id) { - return HawkbitResponseHandler.call("Failed to retrieve metadata for firmware target '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve metadata for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().getMetadata(id)); } @Override public Response getAssignedDs(RequestParams requestParams, String id) { - return HawkbitResponseHandler.call("Failed to retrieve assigned DS for firmware target '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve assigned DS for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().getAssignedDs(id)); } @Override public Response getInstalledDs(RequestParams requestParams, String id) { - return HawkbitResponseHandler.call("Failed to retrieve installed DS for firmware target '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve installed DS for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().getInstalledDs(id)); } @Override public Response getActions(RequestParams requestParams, String id, Integer offset, Integer limit) { - return HawkbitResponseHandler.call("Failed to retrieve actions for firmware target '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to retrieve actions for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().getActions(id, offset, limit)); } @Override public Response getAction(RequestParams requestParams, String id, Long actionId) { - return HawkbitResponseHandler.call( + return HawkbitResponseProxy.proxy( "Failed to retrieve action '" + actionId + "' for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().getAction(id, actionId)); } @Override public void cancelAction(RequestParams requestParams, String id, Long actionId, Boolean force) { - HawkbitResponseHandler.call( + HawkbitResponseProxy.proxy( "Failed to cancel action '" + actionId + "' for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().cancelAction(id, actionId, force)); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/AutoAssignDistributionSetRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/AutoAssignDistributionSetRequest.java deleted file mode 100644 index eec1090..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/AutoAssignDistributionSetRequest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.hawkbit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record AutoAssignDistributionSetRequest( - Long id, - String type, - Integer weight, - Boolean confirmationRequired) { -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetAssignmentRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetAssignmentRequest.java deleted file mode 100644 index af65ef6..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetAssignmentRequest.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.hawkbit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record DistributionSetAssignmentRequest( - String id, - String type, - Long forcetime, - Integer weight, - Boolean confirmationRequired) { -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetCreateRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetCreateRequest.java deleted file mode 100644 index 38e7977..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetCreateRequest.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.hawkbit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record DistributionSetCreateRequest( - String name, - String version, - String type, - String description, - SoftwareModuleReferenceRequest[] modules) { -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetTypeCreateRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetTypeCreateRequest.java deleted file mode 100644 index 1e6e0f6..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/DistributionSetTypeCreateRequest.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.hawkbit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record DistributionSetTypeCreateRequest( - String name, - String key, - String description, - SoftwareModuleReferenceRequest[] mandatorymodules, - SoftwareModuleReferenceRequest[] optionalmodules) { -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutActionRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutActionRequest.java deleted file mode 100644 index 4bde20d..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutActionRequest.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.hawkbit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record RolloutActionRequest(String action, String expression) { -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutConditionRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutConditionRequest.java deleted file mode 100644 index 0077489..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutConditionRequest.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.hawkbit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record RolloutConditionRequest(String condition, String expression) { -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutCreateRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutCreateRequest.java deleted file mode 100644 index 33d92a5..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/RolloutCreateRequest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.hawkbit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record RolloutCreateRequest( - String name, - String description, - String targetFilterQuery, - Long distributionSetId, - Integer amountGroups, - Long forcetime, - Long startAt, - Integer weight, - String type, - RolloutConditionRequest successCondition, - RolloutActionRequest successAction, - RolloutConditionRequest errorCondition, - RolloutActionRequest errorAction, - Boolean confirmationRequired) { -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleCreateRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleCreateRequest.java deleted file mode 100644 index e5e040e..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleCreateRequest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.hawkbit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record SoftwareModuleCreateRequest( - String name, - String version, - String type, - String description, - String vendor, - Boolean encrypted) { -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleReferenceRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleReferenceRequest.java deleted file mode 100644 index d7d11fb..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleReferenceRequest.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.hawkbit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record SoftwareModuleReferenceRequest(Long id) { -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleTypeCreateRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleTypeCreateRequest.java deleted file mode 100644 index 75d18cc..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/SoftwareModuleTypeCreateRequest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.hawkbit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record SoftwareModuleTypeCreateRequest( - String name, - String key, - String description, - Integer maxAssignments) { -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetFilterCreateRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetFilterCreateRequest.java deleted file mode 100644 index 0876a5f..0000000 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetFilterCreateRequest.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2025, OpenRemote Inc. - * - * See the CONTRIBUTORS.txt file in the distribution for a - * full listing of individual contributors. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.openremote.extension.hawkbit.model.hawkbit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record TargetFilterCreateRequest(String name, String query) { -} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java index 017a8f9..038b979 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java @@ -19,12 +19,11 @@ */ package org.openremote.extension.hawkbit.model.resource; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetAssignmentRequest; -import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -39,7 +38,7 @@ public interface DistributionSetResource { @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createDistributionSet(@BeanParam RequestParams requestParams, - DistributionSetCreateRequest distributionSet); + JsonNode distributionSet); @POST @Path("{id}/assign") @@ -49,7 +48,7 @@ Response createDistributionSet(@BeanParam RequestParams requestParams, Response assignDistributionSet(@BeanParam RequestParams requestParams, @PathParam("id") Long id, @QueryParam("offline") Boolean offline, - DistributionSetAssignmentRequest[] targets); + JsonNode targets); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java index b10fd83..96b6892 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java @@ -19,11 +19,11 @@ */ package org.openremote.extension.hawkbit.model.resource; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.hawkbit.DistributionSetTypeCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -38,7 +38,7 @@ public interface DistributionSetTypeResource { @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createDistributionSetType(@BeanParam RequestParams requestParams, - DistributionSetTypeCreateRequest distributionSetType); + JsonNode distributionSetType); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java index e5edf5d..b277de1 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java @@ -19,11 +19,11 @@ */ package org.openremote.extension.hawkbit.model.resource; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.hawkbit.RolloutCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -52,7 +52,7 @@ Response getRollout(@BeanParam RequestParams requestParams, @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createRollout(@BeanParam RequestParams requestParams, - RolloutCreateRequest rollout); + JsonNode rollout); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java index 566c3fc..fcb73cb 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java @@ -19,12 +19,12 @@ */ package org.openremote.extension.hawkbit.model.resource; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.*; import jakarta.ws.rs.core.EntityPart; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -42,7 +42,7 @@ public interface SoftwareModuleResource { @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createSoftwareModule(@BeanParam RequestParams requestParams, - SoftwareModuleCreateRequest softwareModule); + JsonNode softwareModule); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java index 1e86634..eed919e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java @@ -19,11 +19,11 @@ */ package org.openremote.extension.hawkbit.model.resource; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.hawkbit.SoftwareModuleTypeCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -38,7 +38,7 @@ public interface SoftwareModuleTypeResource { @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createSoftwareModuleType(@BeanParam RequestParams requestParams, - SoftwareModuleTypeCreateRequest softwareModuleType); + JsonNode softwareModuleType); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java index 1a74b0e..a11fe4f 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java @@ -19,12 +19,11 @@ */ package org.openremote.extension.hawkbit.model.resource; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import org.openremote.extension.hawkbit.model.hawkbit.AutoAssignDistributionSetRequest; -import org.openremote.extension.hawkbit.model.hawkbit.TargetFilterCreateRequest; import org.openremote.model.Constants; import org.openremote.model.http.RequestParams; @@ -53,7 +52,7 @@ Response getTargetFilter(@BeanParam RequestParams requestParams, @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createTargetFilter(@BeanParam RequestParams requestParams, - TargetFilterCreateRequest filter); + JsonNode filter); @DELETE @Path("{id}") @@ -75,7 +74,7 @@ Response getAutoAssignDS(@BeanParam RequestParams requestParams, @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response setAutoAssignDS(@BeanParam RequestParams requestParams, @PathParam("id") Long id, - AutoAssignDistributionSetRequest request); + JsonNode request); @DELETE @Path("{id}/autoAssignDS") diff --git a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitResponseHandlerTest.groovy b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitResponseProxyTest.groovy similarity index 51% rename from hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitResponseHandlerTest.groovy rename to hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitResponseProxyTest.groovy index b6ae0dd..4dfadfb 100644 --- a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitResponseHandlerTest.groovy +++ b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitResponseProxyTest.groovy @@ -26,9 +26,9 @@ import jakarta.ws.rs.core.Response import org.openremote.model.util.ValueUtil import spock.lang.Specification -class HawkbitResponseHandlerTest extends Specification { +class HawkbitResponseProxyTest extends Specification { - def "strips HAL fields from single resource response"() { + def "preserves JSON response body and media type"() { given: "a hawkBit HAL resource response" def upstream = jsonResponse(''' { @@ -49,46 +49,22 @@ class HawkbitResponseHandlerTest extends Specification { } ''') - when: "the response is adapted" - def formatted = HawkbitResponseHandler.call("Failed to call hawkBit", { upstream }) + when: "the response is copied" + def formatted = HawkbitResponseProxy.proxy("Failed to call hawkBit", { upstream }) def body = readJson(formatted) - then: "HAL fields are removed and normal fields are preserved" + then: "the original JSON body and media type are preserved" formatted.status == 200 formatted.mediaType == MediaType.APPLICATION_JSON_TYPE body.path("id").asInt() == 42 body.path("name").asText() == "target-a" body.path("nested").path("enabled").asBoolean() - !body.has("_links") - !body.has("_embedded") - !body.path("nested").has("_links") + body.path("_links").path("self").path("href").asText() == "http://hawkbit/rest/v1/targets/42" + body.path("_embedded").path("ignored").size() == 1 + body.path("nested").path("_links").path("self").path("href").asText() == "http://hawkbit/rest/v1/nested/7" } - def "maps distribution set link to explicit fields"() { - given: "a hawkBit resource response with a distribution set link" - def upstream = jsonResponse(''' - { - "id": 7, - "_links": { - "distributionset": { - "href": "http://hawkbit/rest/v1/distributionsets/123", - "name": "Release 1.2.3" - } - } - } - ''') - - when: "the response is adapted" - def body = readJson(HawkbitResponseHandler.call("Failed to call hawkBit", { upstream })) - - then: "the link is represented as explicit fields" - body.path("id").asInt() == 7 - body.path("distributionSetId").asLong() == 123L - body.path("distributionSetName").asText() == "Release 1.2.3" - !body.has("_links") - } - - def "flattens embedded HAL collection to paged response"() { + def "preserves embedded HAL collection response"() { given: "a hawkBit HAL collection response" def upstream = jsonResponse(''' { @@ -105,65 +81,15 @@ class HawkbitResponseHandlerTest extends Specification { } ''') - when: "the response is adapted" - def body = readJson(HawkbitResponseHandler.call("Failed to call hawkBit", { upstream })) - - then: "embedded items become page content and HAL fields are stripped" - body.path("total").asInt() == 10 - body.path("size").asInt() == 2 - body.path("content").size() == 2 - body.path("content").get(0).path("controllerId").asText() == "target-a" - body.path("content").get(1).path("controllerId").asText() == "target-b" - !body.path("content").get(0).has("_links") - !body.path("content").get(1).has("_embedded") - } - - def "flattens root array to paged response"() { - given: "a JSON array response" - def upstream = jsonResponse(''' - [ - {"id": 1, "_links": {"self": {"href": "http://hawkbit/rest/v1/items/1"}}}, - {"id": 2} - ] - ''') - - when: "the response is adapted" - def body = readJson(HawkbitResponseHandler.call("Failed to call hawkBit", { upstream })) - - then: "array items become page content" - body.path("total").asInt() == 2 - body.path("size").asInt() == 2 - body.path("content").size() == 2 - body.path("content").get(0).path("id").asInt() == 1 - body.path("content").get(1).path("id").asInt() == 2 - !body.path("content").get(0).has("_links") - } - - def "flattens content array to paged response"() { - given: "a Spring Data REST paged response" - def upstream = jsonResponse(''' - { - "content": [ - {"id": 3, "_links": {"self": {"href": "http://hawkbit/rest/v1/items/3"}}}, - {"id": 4} - ], - "page": { - "totalElements": 5, - "size": 2 - } - } - ''') - - when: "the response is adapted" - def body = readJson(HawkbitResponseHandler.call("Failed to call hawkBit", { upstream })) + when: "the response is copied" + def body = readJson(HawkbitResponseProxy.proxy("Failed to call hawkBit", { upstream })) - then: "content items are preserved and HAL fields are stripped" - body.path("total").asInt() == 5 - body.path("size").asInt() == 2 - body.path("content").size() == 2 - body.path("content").get(0).path("id").asInt() == 3 - body.path("content").get(1).path("id").asInt() == 4 - !body.path("content").get(0).has("_links") + then: "embedded items and page metadata stay in hawkBit's shape" + body.path("_embedded").path("targets").size() == 2 + body.path("_embedded").path("targets").get(0).path("controllerId").asText() == "target-a" + body.path("_embedded").path("targets").get(0).path("_links").path("self").path("href").asText() == "http://hawkbit/rest/v1/targets/target-a" + body.path("page").path("totalElements").asInt() == 10 + body.path("page").path("size").asInt() == 2 } def "preserves non-JSON body and media type"() { @@ -173,8 +99,8 @@ class HawkbitResponseHandlerTest extends Specification { .entity("upstream unavailable") .build() - when: "the response is adapted" - def formatted = HawkbitResponseHandler.call("Failed to call hawkBit", { upstream }) + when: "the response is copied" + def formatted = HawkbitResponseProxy.proxy("Failed to call hawkBit", { upstream }) then: "the original body and media type are preserved" formatted.status == Response.Status.BAD_GATEWAY.statusCode @@ -186,8 +112,8 @@ class HawkbitResponseHandlerTest extends Specification { given: "an upstream response without an entity" def upstream = Response.noContent().build() - when: "the response is adapted" - def formatted = HawkbitResponseHandler.call("Failed to call hawkBit", { upstream }) + when: "the response is copied" + def formatted = HawkbitResponseProxy.proxy("Failed to call hawkBit", { upstream }) then: "the empty status is preserved" formatted.status == Response.Status.NO_CONTENT.statusCode @@ -195,8 +121,8 @@ class HawkbitResponseHandlerTest extends Specification { } def "wraps checked exceptions as bad gateway"() { - when: "an adapted call throws an unexpected exception" - HawkbitResponseHandler.call("Failed to call hawkBit", { + when: "a hawkBit call throws an unexpected exception" + HawkbitResponseProxy.proxy("Failed to call hawkBit", { throw new IOException("connection failed") }) @@ -211,8 +137,8 @@ class HawkbitResponseHandlerTest extends Specification { given: "an existing web application exception" def original = new WebApplicationException("not found", Response.Status.NOT_FOUND) - when: "an adapted call throws it" - HawkbitResponseHandler.call("Failed to call hawkBit", { + when: "a hawkBit call throws it" + HawkbitResponseProxy.proxy("Failed to call hawkBit", { throw original }) From 77b19d94c2be53286cb49cc4282b656c4eb13d26 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Mon, 18 May 2026 13:16:38 +0200 Subject: [PATCH 12/18] Add javadocs, add realm guard for all endpoints --- hawkbit/README.md | 6 ++ .../manager/HawkbitFirmwareService.java | 7 ++ .../resource/DistributionSetResourceImpl.java | 28 ++++---- .../DistributionSetTypeResourceImpl.java | 37 ++++++----- .../manager/resource/HawkbitWebResource.java | 66 +++++++++++++++++++ .../manager/resource/RolloutResourceImpl.java | 38 ++++++----- .../resource/SoftwareModuleResourceImpl.java | 28 ++++---- .../SoftwareModuleTypeResourceImpl.java | 25 +++---- .../resource/TargetFilterResourceImpl.java | 32 +++++---- .../manager/resource/TargetResourceImpl.java | 34 +++++----- .../resource/DistributionSetResource.java | 30 +++++++-- .../resource/DistributionSetTypeResource.java | 49 ++++++++++---- .../model/resource/RolloutResource.java | 60 ++++++++++++----- .../resource/SoftwareModuleResource.java | 40 ++++++++--- .../resource/SoftwareModuleTypeResource.java | 23 +++++-- .../model/resource/TargetFilterResource.java | 41 +++++++++--- .../model/resource/TargetResource.java | 45 +++++++++++-- 17 files changed, 433 insertions(+), 156 deletions(-) create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/HawkbitWebResource.java diff --git a/hawkbit/README.md b/hawkbit/README.md index f8e560d..853da4e 100644 --- a/hawkbit/README.md +++ b/hawkbit/README.md @@ -6,6 +6,12 @@ This extension connects OpenRemote Manager to the hawkBit Management API, exposes firmware endpoints in OpenRemote, and syncs selected assets as hawkBit targets. +## Limitations + +**Single realm only.** The extension is bound at startup to one OpenRemote realm, set by `HAWKBIT_REALM` (default `master`). Asset sync, metadata sync, and the firmware API endpoints only operate on that realm. Callers from other realms get `403`. + +Multi-tenant deployments are not supported, and is currently out of scope. + ## Prerequisites You need: diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java index ba8e39b..783b046 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java @@ -521,6 +521,13 @@ public Response uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream form)); } + /** + * Returns the realm this service is bound to. Firmware endpoints are scoped to it. + */ + public String getRealm() { + return hawkbitRealm; + } + /** * Returns the hawkBit targets client. */ diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java index 5d8726c..2e3aab5 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java @@ -27,31 +27,30 @@ import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.DistributionSetResource; import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -public class DistributionSetResourceImpl extends ManagerWebResource +public class DistributionSetResourceImpl extends HawkbitWebResource implements DistributionSetResource { - protected final HawkbitFirmwareService hawkbitFirmwareService; - public DistributionSetResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { - super(timerService, identityService); - this.hawkbitFirmwareService = hawkbitFirmwareService; + HawkbitFirmwareService hawkbitFirmwareService) { + super(timerService, identityService, hawkbitFirmwareService); } @Override public Response createDistributionSet(RequestParams requestParams, + String realm, JsonNode distributionSet) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to create firmware distribution set", () -> hawkbitFirmwareService.distributionSets().create(distributionSet)); } @Override - public Response assignDistributionSet(RequestParams requestParams, Long id, - Boolean offline, - JsonNode targets) { + public Response assignDistributionSet(RequestParams requestParams, String realm, Long id, + Boolean offline, + JsonNode targets) { + requireHawkbitRealmAccess(realm); if (targets == null || !targets.isArray() || targets.isEmpty()) { throw new WebApplicationException("Assignment requires at least one target", Response.Status.BAD_REQUEST); } @@ -60,19 +59,22 @@ public Response assignDistributionSet(RequestParams requestParams, Long id, } @Override - public Response getDistributionSets(RequestParams requestParams, Integer offset, Integer limit) { + public Response getDistributionSets(RequestParams requestParams, String realm, Integer offset, Integer limit) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware distribution sets", () -> hawkbitFirmwareService.distributionSets().getDistributionSets(offset, limit)); } @Override - public Response getDistributionSet(RequestParams requestParams, Long id) { + public Response getDistributionSet(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware distribution set '" + id + "'", () -> hawkbitFirmwareService.distributionSets().get(id)); } @Override - public void deleteDistributionSet(RequestParams requestParams, Long id) { + public void deleteDistributionSet(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); HawkbitResponseProxy.proxy("Failed to delete firmware distribution set '" + id + "'", () -> hawkbitFirmwareService.distributionSets().delete(id)); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java index fe22bfe..f20a79e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java @@ -26,59 +26,62 @@ import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.DistributionSetTypeResource; import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -public class DistributionSetTypeResourceImpl extends ManagerWebResource +public class DistributionSetTypeResourceImpl extends HawkbitWebResource implements DistributionSetTypeResource { - protected final HawkbitFirmwareService hawkbitFirmwareService; - public DistributionSetTypeResourceImpl(TimerService timerService, - ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { - super(timerService, identityService); - this.hawkbitFirmwareService = hawkbitFirmwareService; + ManagerIdentityService identityService, + HawkbitFirmwareService hawkbitFirmwareService) { + super(timerService, identityService, hawkbitFirmwareService); } @Override public Response createDistributionSetType(RequestParams requestParams, - JsonNode distributionSetType) { + String realm, + JsonNode distributionSetType) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to create firmware distribution set type", () -> hawkbitFirmwareService.distributionSetTypes().create(distributionSetType)); } @Override - public Response getDistributionSetTypes(RequestParams requestParams, Integer offset, - Integer limit) { + public Response getDistributionSetTypes(RequestParams requestParams, String realm, Integer offset, + Integer limit) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware distribution set types", () -> hawkbitFirmwareService.distributionSetTypes().getDistributionSetTypes(offset, limit)); } @Override - public Response getDistributionSetType(RequestParams requestParams, Long id) { + public Response getDistributionSetType(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware distribution set type '" + id + "'", () -> hawkbitFirmwareService.distributionSetTypes().get(id)); } @Override - public Response getMandatoryModuleTypes(RequestParams requestParams, Long id, Integer offset, - Integer limit) { + public Response getMandatoryModuleTypes(RequestParams requestParams, String realm, Long id, Integer offset, + Integer limit) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy( "Failed to retrieve mandatory module types for firmware distribution set type '" + id + "'", () -> hawkbitFirmwareService.distributionSetTypes().getMandatoryModuleTypes(id, offset, limit)); } @Override - public Response getOptionalModuleTypes(RequestParams requestParams, Long id, Integer offset, - Integer limit) { + public Response getOptionalModuleTypes(RequestParams requestParams, String realm, Long id, Integer offset, + Integer limit) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy( "Failed to retrieve optional module types for firmware distribution set type '" + id + "'", () -> hawkbitFirmwareService.distributionSetTypes().getOptionalModuleTypes(id, offset, limit)); } @Override - public void deleteDistributionSetType(RequestParams requestParams, Long id) { + public void deleteDistributionSetType(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); HawkbitResponseProxy.proxy("Failed to delete firmware distribution set type '" + id + "'", () -> hawkbitFirmwareService.distributionSetTypes().delete(id)); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/HawkbitWebResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/HawkbitWebResource.java new file mode 100644 index 0000000..1f746d3 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/HawkbitWebResource.java @@ -0,0 +1,66 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.manager.resource; + +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.ForbiddenException; +import org.openremote.container.timer.TimerService; +import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; +import org.openremote.manager.security.ManagerIdentityService; +import org.openremote.manager.web.ManagerWebResource; + +import java.util.Objects; + +/** + * Base resource for hawkBit Management API proxy endpoints. + *

+ * The request path realm remains the OpenRemote authentication realm. The hawkBit target realm is supplied explicitly by + * each endpoint, matching manager APIs that allow superusers authenticated on {@code master} to operate on another realm. + */ +public abstract class HawkbitWebResource extends ManagerWebResource { + + protected final HawkbitFirmwareService hawkbitFirmwareService; + + protected HawkbitWebResource(TimerService timerService, ManagerIdentityService identityService, + HawkbitFirmwareService hawkbitFirmwareService) { + super(timerService, identityService); + this.hawkbitFirmwareService = hawkbitFirmwareService; + } + + /** + * Verifies that the requested hawkBit realm is present, accessible to the caller, and is the realm configured for + * this hawkBit integration. + * + * @param realm target OpenRemote realm for firmware management + * @throws BadRequestException if no target realm was supplied + * @throws ForbiddenException if the caller cannot access the realm, or hawkBit is not configured for that realm + */ + protected void requireHawkbitRealmAccess(String realm) { + if (realm == null || realm.isBlank()) { + throw new BadRequestException("Firmware realm is required"); + } + if (!isRealmActiveAndAccessible(realm)) { + throw new ForbiddenException("Realm '" + realm + "' is nonexistent, inactive or inaccessible"); + } + if (!Objects.equals(realm, hawkbitFirmwareService.getRealm())) { + throw new ForbiddenException("Firmware management is not available for this realm"); + } + } +} diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java index 58ab455..d6d2947 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java @@ -26,66 +26,70 @@ import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.RolloutResource; import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -public class RolloutResourceImpl extends ManagerWebResource +public class RolloutResourceImpl extends HawkbitWebResource implements RolloutResource { - protected final HawkbitFirmwareService hawkbitFirmwareService; - public RolloutResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { - super(timerService, identityService); - this.hawkbitFirmwareService = hawkbitFirmwareService; + HawkbitFirmwareService hawkbitFirmwareService) { + super(timerService, identityService, hawkbitFirmwareService); } @Override - public Response getRollouts(RequestParams requestParams, Integer offset, Integer limit) { + public Response getRollouts(RequestParams requestParams, String realm, Integer offset, Integer limit) { + requireHawkbitRealmAccess(realm); // Request full representation so totalTargetsPerStatus and totalGroups are populated; hawkBit defaults to compact. return HawkbitResponseProxy.proxy("Failed to retrieve firmware rollouts", () -> hawkbitFirmwareService.rollouts().getRollouts(offset, limit, "full")); } @Override - public Response getRollout(RequestParams requestParams, Long id) { + public Response getRollout(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().get(id)); } @Override - public Response createRollout(RequestParams requestParams, JsonNode rollout) { + public Response createRollout(RequestParams requestParams, String realm, JsonNode rollout) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to create firmware rollout", () -> hawkbitFirmwareService.rollouts().create(rollout)); } @Override - public void deleteRollout(RequestParams requestParams, Long id) { + public void deleteRollout(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); HawkbitResponseProxy.proxy("Failed to delete firmware rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().delete(id)); } @Override - public Response startRollout(RequestParams requestParams, Long id) { - return HawkbitResponseProxy.proxy("Failed to start firmware rollout '" + id + "'", + public void startRollout(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); + HawkbitResponseProxy.proxy("Failed to start firmware rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().start(id)); } @Override - public void pauseRollout(RequestParams requestParams, Long id) { + public void pauseRollout(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); HawkbitResponseProxy.proxy("Failed to pause firmware rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().pause(id)); } @Override - public Response getRolloutGroups(RequestParams requestParams, Long id, - Integer offset, Integer limit) { + public Response getRolloutGroups(RequestParams requestParams, String realm, Long id, + Integer offset, Integer limit) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve groups for rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().getRolloutGroups(id, offset, limit, "full")); } @Override - public Response getRolloutGroup(RequestParams requestParams, Long id, Long groupId) { + public Response getRolloutGroup(RequestParams requestParams, String realm, Long id, Long groupId) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy( "Failed to retrieve group '" + groupId + "' for rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().getRolloutGroup(id, groupId)); diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java index 96920c9..a2da4a8 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java @@ -28,53 +28,56 @@ import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.SoftwareModuleResource; import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; import java.io.InputStream; import java.util.List; -public class SoftwareModuleResourceImpl extends ManagerWebResource +public class SoftwareModuleResourceImpl extends HawkbitWebResource implements SoftwareModuleResource { - protected final HawkbitFirmwareService hawkbitFirmwareService; - public SoftwareModuleResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { - super(timerService, identityService); - this.hawkbitFirmwareService = hawkbitFirmwareService; + HawkbitFirmwareService hawkbitFirmwareService) { + super(timerService, identityService, hawkbitFirmwareService); } @Override public Response createSoftwareModule(RequestParams requestParams, - JsonNode softwareModule) { + String realm, + JsonNode softwareModule) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to create firmware software module", () -> hawkbitFirmwareService.softwareModules().create(softwareModule)); } @Override - public Response getSoftwareModules(RequestParams requestParams, Integer offset, Integer limit) { + public Response getSoftwareModules(RequestParams requestParams, String realm, Integer offset, Integer limit) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware software modules", () -> hawkbitFirmwareService.softwareModules().getSoftwareModules(offset, limit)); } @Override - public Response getSoftwareModule(RequestParams requestParams, Long id) { + public Response getSoftwareModule(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware software module '" + id + "'", () -> hawkbitFirmwareService.softwareModules().get(id)); } @Override - public Response getSoftwareModuleArtifacts(RequestParams requestParams, Long id) { + public Response getSoftwareModuleArtifacts(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve artifacts for firmware software module '" + id + "'", () -> hawkbitFirmwareService.softwareModules().getArtifacts(id)); } @Override public Response uploadSoftwareModuleArtifact(RequestParams requestParams, + String realm, Long id, String filename, List parts) { + requireHawkbitRealmAccess(realm); try { EntityPart filePart = parts == null ? null : parts.stream() .filter(part -> "file".equals(part.getName())) @@ -96,7 +99,8 @@ public Response uploadSoftwareModuleArtifact(RequestParams requestParams, } @Override - public void deleteSoftwareModule(RequestParams requestParams, Long id) { + public void deleteSoftwareModule(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); HawkbitResponseProxy.proxy("Failed to delete firmware software module '" + id + "'", () -> hawkbitFirmwareService.softwareModules().delete(id)); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java index 0b11054..eb8500d 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java @@ -26,42 +26,43 @@ import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.SoftwareModuleTypeResource; import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -public class SoftwareModuleTypeResourceImpl extends ManagerWebResource +public class SoftwareModuleTypeResourceImpl extends HawkbitWebResource implements SoftwareModuleTypeResource { - protected final HawkbitFirmwareService hawkbitFirmwareService; - public SoftwareModuleTypeResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { - super(timerService, identityService); - this.hawkbitFirmwareService = hawkbitFirmwareService; + HawkbitFirmwareService hawkbitFirmwareService) { + super(timerService, identityService, hawkbitFirmwareService); } @Override public Response createSoftwareModuleType(RequestParams requestParams, - JsonNode softwareModuleType) { + String realm, + JsonNode softwareModuleType) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to create firmware software module type", () -> hawkbitFirmwareService.softwareModuleTypes().create(softwareModuleType)); } @Override - public Response getSoftwareModuleTypes(RequestParams requestParams, Integer offset, - Integer limit) { + public Response getSoftwareModuleTypes(RequestParams requestParams, String realm, Integer offset, + Integer limit) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware software module types", () -> hawkbitFirmwareService.softwareModuleTypes().getSoftwareModuleTypes(offset, limit)); } @Override - public Response getSoftwareModuleType(RequestParams requestParams, Long id) { + public Response getSoftwareModuleType(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware software module type '" + id + "'", () -> hawkbitFirmwareService.softwareModuleTypes().get(id)); } @Override - public void deleteSoftwareModuleType(RequestParams requestParams, Long id) { + public void deleteSoftwareModuleType(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); HawkbitResponseProxy.proxy("Failed to delete firmware software module type '" + id + "'", () -> hawkbitFirmwareService.softwareModuleTypes().delete(id)); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java index e30fa23..e038049 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java @@ -26,62 +26,66 @@ import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.TargetFilterResource; import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -public class TargetFilterResourceImpl extends ManagerWebResource +public class TargetFilterResourceImpl extends HawkbitWebResource implements TargetFilterResource { - protected final HawkbitFirmwareService hawkbitFirmwareService; - public TargetFilterResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { - super(timerService, identityService); - this.hawkbitFirmwareService = hawkbitFirmwareService; + HawkbitFirmwareService hawkbitFirmwareService) { + super(timerService, identityService, hawkbitFirmwareService); } @Override - public Response getTargetFilters(RequestParams requestParams, Integer offset, Integer limit) { + public Response getTargetFilters(RequestParams requestParams, String realm, Integer offset, Integer limit) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware target filters", () -> hawkbitFirmwareService.targetFilters().getTargetFilters(offset, limit)); } @Override - public Response getTargetFilter(RequestParams requestParams, Long id) { + public Response getTargetFilter(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware target filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().get(id)); } @Override public Response createTargetFilter(RequestParams requestParams, + String realm, JsonNode filter) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to create firmware target filter", () -> hawkbitFirmwareService.targetFilters().create(filter)); } @Override - public void deleteTargetFilter(RequestParams requestParams, Long id) { + public void deleteTargetFilter(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); HawkbitResponseProxy.proxy("Failed to delete firmware target filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().delete(id)); } @Override - public Response getAutoAssignDS(RequestParams requestParams, Long id) { + public Response getAutoAssignDS(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy( "Failed to retrieve auto assign distribution set for filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().getAutoAssignDS(id)); } @Override - public Response setAutoAssignDS(RequestParams requestParams, Long id, - JsonNode request) { + public Response setAutoAssignDS(RequestParams requestParams, String realm, Long id, + JsonNode request) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy( "Failed to set auto assign distribution set for filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().setAutoAssignDS(id, request)); } @Override - public void deleteAutoAssignDS(RequestParams requestParams, Long id) { + public void deleteAutoAssignDS(RequestParams requestParams, String realm, Long id) { + requireHawkbitRealmAccess(realm); HawkbitResponseProxy.proxy( "Failed to remove auto assign distribution set from filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().deleteAutoAssignDS(id)); diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java index ec66f6c..4c69e21 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java @@ -25,64 +25,68 @@ import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; import org.openremote.extension.hawkbit.model.resource.TargetResource; import org.openremote.manager.security.ManagerIdentityService; -import org.openremote.manager.web.ManagerWebResource; import org.openremote.model.http.RequestParams; -public class TargetResourceImpl extends ManagerWebResource implements TargetResource { - - protected final HawkbitFirmwareService hawkbitFirmwareService; +public class TargetResourceImpl extends HawkbitWebResource implements TargetResource { public TargetResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { - super(timerService, identityService); - this.hawkbitFirmwareService = hawkbitFirmwareService; + HawkbitFirmwareService hawkbitFirmwareService) { + super(timerService, identityService, hawkbitFirmwareService); } @Override - public Response getTargets(RequestParams requestParams, String query, Integer offset, Integer limit) { + public Response getTargets(RequestParams requestParams, String realm, String query, Integer offset, Integer limit) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware targets", () -> hawkbitFirmwareService.targets().getTargets(query, offset, limit)); } @Override - public Response getTarget(RequestParams requestParams, String id) { + public Response getTarget(RequestParams requestParams, String realm, String id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().get(id)); } @Override - public Response getMetadata(RequestParams requestParams, String id) { + public Response getMetadata(RequestParams requestParams, String realm, String id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve metadata for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().getMetadata(id)); } @Override - public Response getAssignedDs(RequestParams requestParams, String id) { + public Response getAssignedDs(RequestParams requestParams, String realm, String id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve assigned DS for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().getAssignedDs(id)); } @Override - public Response getInstalledDs(RequestParams requestParams, String id) { + public Response getInstalledDs(RequestParams requestParams, String realm, String id) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve installed DS for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().getInstalledDs(id)); } @Override - public Response getActions(RequestParams requestParams, String id, Integer offset, Integer limit) { + public Response getActions(RequestParams requestParams, String realm, String id, Integer offset, Integer limit) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve actions for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().getActions(id, offset, limit)); } @Override - public Response getAction(RequestParams requestParams, String id, Long actionId) { + public Response getAction(RequestParams requestParams, String realm, String id, Long actionId) { + requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy( "Failed to retrieve action '" + actionId + "' for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().getAction(id, actionId)); } @Override - public void cancelAction(RequestParams requestParams, String id, Long actionId, Boolean force) { + public void cancelAction(RequestParams requestParams, String realm, String id, Long actionId, Boolean force) { + requireHawkbitRealmAccess(realm); HawkbitResponseProxy.proxy( "Failed to cancel action '" + actionId + "' for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().cancelAction(id, actionId, force)); diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java index 038b979..f0cd214 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java @@ -29,42 +29,64 @@ import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +/** + * Proxies the hawkBit Management API distribution-set endpoints. + *

+ * Delegates to {@link org.openremote.extension.hawkbit.manager.hawkbit.HawkbitDistributionSetsClient} + * and returns the upstream response body unchanged. + */ @Tag(name = "Firmware Distribution Sets", description = "Management of firmware distribution sets") @Path("firmware/distributionset") public interface DistributionSetResource { + /** Create a distribution set. Body is a hawkBit DistributionSet create payload. */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createDistributionSet(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, JsonNode distributionSet); + /** + * Assign a distribution set to one or more firmware targets. + *

+ * {@code targets} must be a non-empty JSON array. Empty or non-array bodies + * return {@code 400}. + *

+ * {@code offline=true} records the assignment as already-installed and skips + * the controller download step. Use this when the target was flashed out-of-band. + */ @POST @Path("{id}/assign") @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response assignDistributionSet(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, @PathParam("id") Long id, @QueryParam("offline") Boolean offline, JsonNode targets); + /** Retrieve all distribution sets, paged. */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getDistributionSets(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("realm") String realm, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + /** Retrieve a single distribution set by id. */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - Response getDistributionSet(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + Response getDistributionSet(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); + /** Delete a distribution set. */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void deleteDistributionSet(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + void deleteDistributionSet(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java index 96b6892..a0ba350 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java @@ -29,51 +29,78 @@ import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +/** + * Proxies the hawkBit Management API distribution-set-type endpoints. + *

+ * Delegates to {@link org.openremote.extension.hawkbit.manager.hawkbit.HawkbitDistributionSetTypesClient} + * and returns the upstream response body unchanged. + */ @Tag(name = "Firmware Distribution Set Types", description = "Management of firmware distribution set types") @Path("firmware/distributionsettype") public interface DistributionSetTypeResource { + /** Create a distribution-set type. Body is a hawkBit DistributionSetType create payload. */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createDistributionSetType(@BeanParam RequestParams requestParams, - JsonNode distributionSetType); + @QueryParam("realm") String realm, + JsonNode distributionSetType); + /** Retrieve all distribution-set types, paged. */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getDistributionSetTypes(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("realm") String realm, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + /** Retrieve a single distribution-set type by id. */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getDistributionSetType(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + @QueryParam("realm") String realm, + @PathParam("id") Long id); + /** + * Retrieve the module types every DS of this type must include. + *

+ * Describes the composition contract of the DS type, not the modules of any + * specific distribution set. + */ @GET @Path("{id}/mandatorymoduletypes") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getMandatoryModuleTypes(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("realm") String realm, + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + /** + * Retrieve the module types that a DS of this type may optionally include. + *

+ * Describes the composition contract of the DS type, not the modules + * of any specific distribution set. See {@link #getMandatoryModuleTypes}. + */ @GET @Path("{id}/optionalmoduletypes") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getOptionalModuleTypes(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("realm") String realm, + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + /** Delete a distribution-set type. */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void deleteDistributionSetType(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + void deleteDistributionSetType(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java index b277de1..3bb0f93 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java @@ -29,65 +29,95 @@ import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +/** + * Proxies the hawkBit Management API rollout endpoints. + *

+ * Delegates to {@link org.openremote.extension.hawkbit.manager.hawkbit.HawkbitRolloutsClient} + * and returns the upstream response body unchanged. + */ @Tag(name = "Firmware Rollouts", description = "Management of firmware rollouts") @Path("firmware/rollout") public interface RolloutResource { + /** + * Retrieve all rollouts, paged. + *

+ * Forces {@code representation=full} so {@code totalTargetsPerStatus} and + * {@code totalGroups} are populated. hawkBit's default is {@code compact} + * which omits both. + */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getRollouts(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("realm") String realm, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + /** Retrieve a single rollout by id. */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getRollout(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + @QueryParam("realm") String realm, + @PathParam("id") Long id); + /** Create a rollout. Body matches hawkBit's Rollout create payload. */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createRollout(@BeanParam RequestParams requestParams, - JsonNode rollout); + @QueryParam("realm") String realm, + JsonNode rollout); + /** Delete a rollout. */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) void deleteRollout(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + @QueryParam("realm") String realm, + @PathParam("id") Long id); + /** Start a rollout. */ @POST @Path("{id}/start") - @Consumes(APPLICATION_JSON) - @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - Response startRollout(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + void startRollout(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, + @PathParam("id") Long id); + /** Pause a running rollout. */ @POST @Path("{id}/pause") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) void pauseRollout(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + @QueryParam("realm") String realm, + @PathParam("id") Long id); + /** + * Retrieve deployment groups for a rollout, paged. + *

+ * Forces {@code representation=full} so per-group status counters are populated. + */ @GET @Path("{id}/deploygroups") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getRolloutGroups(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("realm") String realm, + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + /** Retrieve a single deployment group within a rollout. */ @GET @Path("{id}/deploygroups/{groupId}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getRolloutGroup(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - @PathParam("groupId") Long groupId); + @QueryParam("realm") String realm, + @PathParam("id") Long id, + @PathParam("groupId") Long groupId); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java index fcb73cb..6de84c4 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java @@ -33,49 +33,71 @@ import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static jakarta.ws.rs.core.MediaType.MULTIPART_FORM_DATA; +/** + * Proxies the hawkBit Management API software-module endpoints. + *

+ * Delegates to {@link org.openremote.extension.hawkbit.manager.hawkbit.HawkbitSoftwareModulesClient} + * and returns the upstream response body unchanged. + */ @Tag(name = "Firmware Software Modules", description = "Management of firmware software modules") @Path("firmware/softwaremodule") public interface SoftwareModuleResource { + /** Create a software module. Body matches hawkBit's SoftwareModule create payload. */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createSoftwareModule(@BeanParam RequestParams requestParams, - JsonNode softwareModule); + @QueryParam("realm") String realm, + JsonNode softwareModule); + /** Retrieve all software modules, paged. */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getSoftwareModules(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("realm") String realm, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + /** Retrieve a single software module by id. */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - Response getSoftwareModule(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + Response getSoftwareModule(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); + /** Retrieve all artifacts attached to a software module. */ @GET @Path("{id}/artifacts") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - Response getSoftwareModuleArtifacts(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + Response getSoftwareModuleArtifacts(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); + /** + * Upload an artifact file to a software module. + *

+ * Multipart body must include a part named {@code "file"}. Requests without it + * return {@code 400}. The {@code filename} query parameter overrides the + * filename from the multipart part. If neither is set the upload falls back + * to {@code "artifact.bin"}. + */ @POST @Path("{id}/artifacts") @Consumes(MULTIPART_FORM_DATA) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response uploadSoftwareModuleArtifact(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - @QueryParam("filename") String filename, - List parts); + @QueryParam("realm") String realm, + @PathParam("id") Long id, + @QueryParam("filename") String filename, + List parts); + /** Delete a software module. */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void deleteSoftwareModule(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + void deleteSoftwareModule(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java index eed919e..7b8a2bb 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java @@ -29,33 +29,46 @@ import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +/** + * Proxies the hawkBit Management API software-module-type endpoints. + *

+ * Delegates to {@link org.openremote.extension.hawkbit.manager.hawkbit.HawkbitSoftwareModuleTypesClient} + * and returns the upstream response body unchanged. + */ @Tag(name = "Firmware Software Module Types", description = "Management of firmware software module types") @Path("firmware/softwaremoduletype") public interface SoftwareModuleTypeResource { + /** Create a software-module type. Body matches hawkBit's SoftwareModuleType create payload. */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createSoftwareModuleType(@BeanParam RequestParams requestParams, - JsonNode softwareModuleType); + @QueryParam("realm") String realm, + JsonNode softwareModuleType); + /** Retrieve all software-module types, paged. */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getSoftwareModuleTypes(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("realm") String realm, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + /** Retrieve a single software-module type by id. */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getSoftwareModuleType(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + @QueryParam("realm") String realm, + @PathParam("id") Long id); + /** Delete a software-module type. */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void deleteSoftwareModuleType(@BeanParam RequestParams requestParams, @PathParam("id") Long id); + void deleteSoftwareModuleType(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java index a11fe4f..c722914 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java @@ -29,56 +29,81 @@ import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +/** + * Proxies the hawkBit Management API target-filter endpoints. + *

+ * Delegates to {@link org.openremote.extension.hawkbit.manager.hawkbit.HawkbitTargetFiltersClient} + * and returns the upstream response body unchanged. + */ @Tag(name = "Firmware Target Filters", description = "Management of firmware target filter queries") @Path("firmware/targetfilter") public interface TargetFilterResource { + /** Retrieve all target filter queries, paged. */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getTargetFilters(@BeanParam RequestParams requestParams, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("realm") String realm, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + /** Retrieve a single target filter query by id. */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getTargetFilter(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, @PathParam("id") Long id); + /** Create a target filter query. Body matches hawkBit's TargetFilterQuery create payload. */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createTargetFilter(@BeanParam RequestParams requestParams, - JsonNode filter); + @QueryParam("realm") String realm, + JsonNode filter); + /** Delete a target filter query. */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) void deleteTargetFilter(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + @QueryParam("realm") String realm, + @PathParam("id") Long id); + /** Retrieve the auto-assign distribution set configured for a target filter. */ @GET @Path("{id}/autoAssignDS") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getAutoAssignDS(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + @QueryParam("realm") String realm, + @PathParam("id") Long id); + /** + * Configure the auto-assign distribution set for a target filter. + *

+ * Body matches hawkBit's {@code AutoAssignDistributionSetRequest} shape + * (distribution-set {@code id} plus optional {@code actionType}). + */ @POST @Path("{id}/autoAssignDS") @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response setAutoAssignDS(@BeanParam RequestParams requestParams, - @PathParam("id") Long id, - JsonNode request); + @QueryParam("realm") String realm, + @PathParam("id") Long id, + JsonNode request); + /** Remove the auto-assign distribution set from a target filter. */ @DELETE @Path("{id}/autoAssignDS") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) void deleteAutoAssignDS(@BeanParam RequestParams requestParams, - @PathParam("id") Long id); + @QueryParam("realm") String realm, + @PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java index 5e7d5c3..f64d224 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java @@ -28,63 +28,100 @@ import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +/** + * Proxies the hawkBit Management API target endpoints. + *

+ * Delegates to {@link org.openremote.extension.hawkbit.manager.hawkbit.HawkbitTargetsClient} + * and returns the upstream response body unchanged. + */ @Tag(name = "Firmware Targets", description = "Management of firmware targets") @Path("firmware/target") public interface TargetResource { + /** + * Retrieve firmware targets, paged. + *

+ * {@code q} is a hawkBit RSQL filter (e.g. {@code name==foo}), not free-text search. + */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getTargets(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, @QueryParam("q") String query, @QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit); + /** Retrieve a single firmware target by controllerId. */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - Response getTarget(@BeanParam RequestParams requestParams, @PathParam("id") String id); + Response getTarget(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") String id); + /** Retrieve all metadata key/value pairs for a firmware target. */ @GET @Path("{id}/metadata") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - Response getMetadata(@BeanParam RequestParams requestParams, @PathParam("id") String id); + Response getMetadata(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") String id); + /** + * Retrieve the distribution set currently assigned to a firmware target. + *

+ * "Assigned" is the DS the server has scheduled. See {@link #getInstalledDs} + * for what the target has confirmed installed. + */ @GET @Path("{id}/assignedDS") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - Response getAssignedDs(@BeanParam RequestParams requestParams, @PathParam("id") String id); + Response getAssignedDs(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") String id); + /** + * Retrieve the distribution set currently reported as installed on a firmware target. + *

+ * "Installed" reflects the target's last confirmation. See {@link #getAssignedDs} + * for what the server has scheduled. + */ @GET @Path("{id}/installedDS") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) - Response getInstalledDs(@BeanParam RequestParams requestParams, @PathParam("id") String id); + Response getInstalledDs(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") String id); + /** Retrieve the action history for a firmware target, paged. */ @GET @Path("{id}/actions") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getActions(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, @PathParam("id") String id, @QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit); + /** Retrieve a single action for a firmware target. */ @GET @Path("{id}/actions/{actionId}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getAction(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, @PathParam("id") String id, @PathParam("actionId") Long actionId); + /** + * Cancel an in-flight action on a firmware target. + *

+ * {@code force=true} bypasses the cancel-confirmation handshake with the + * controller. The target stays in an unknown state until its next poll. + */ @DELETE @Path("{id}/actions/{actionId}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) void cancelAction(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, @PathParam("id") String id, @PathParam("actionId") Long actionId, @QueryParam("force") Boolean force); From 07f258682b7afbc7543adb62ded6e052afada68b Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Mon, 18 May 2026 17:15:13 +0200 Subject: [PATCH 13/18] Cleanup --- .../manager/HawkbitFirmwareService.java | 122 +++++++++--------- .../HawkbitDistributionSetsClient.java | 4 +- .../hawkbit/HawkbitRolloutsClient.java | 1 - .../resource/DistributionSetResourceImpl.java | 10 +- .../DistributionSetTypeResourceImpl.java | 18 +-- .../manager/resource/HawkbitWebResource.java | 17 +-- .../manager/resource/RolloutResourceImpl.java | 18 +-- .../resource/SoftwareModuleResourceImpl.java | 19 ++- .../SoftwareModuleTypeResourceImpl.java | 12 +- .../resource/TargetFilterResourceImpl.java | 12 +- .../manager/resource/TargetResourceImpl.java | 13 +- .../resource/DistributionSetResource.java | 24 ++-- .../resource/DistributionSetTypeResource.java | 38 +++--- .../model/resource/RolloutResource.java | 60 +++++---- .../resource/SoftwareModuleResource.java | 34 +++-- .../resource/SoftwareModuleTypeResource.java | 26 ++-- .../model/resource/TargetFilterResource.java | 48 ++++--- .../model/resource/TargetResource.java | 34 +++-- .../manager/HawkbitFirmwareServiceTest.groovy | 27 +++- 19 files changed, 322 insertions(+), 215 deletions(-) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java index 783b046..6791744 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java @@ -19,16 +19,13 @@ */ package org.openremote.extension.hawkbit.manager; -import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.client.ClientRequestFilter; import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; import org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider; -import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataWriter; import org.openremote.container.timer.TimerService; import org.openremote.container.web.WebClient; @@ -54,9 +51,7 @@ import org.openremote.model.syslog.SyslogCategory; import org.openremote.model.util.TextUtil; import org.openremote.model.util.ValueUtil; -import org.openremote.model.value.AttributeDescriptor; -import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.*; @@ -69,10 +64,14 @@ import static org.openremote.model.util.MapAccess.getString; public class HawkbitFirmwareService implements ContainerService { - - + /** + * hawkBit integration is currently limited to a single realm, + * this is due to hawkBit's tenancy model being difficult to work with because of + * the authentication/security mechanisms that are in place. + */ public static final String HAWKBIT_REALM = "HAWKBIT_REALM"; public static final String HAWKBIT_REALM_DEFAULT = "master"; + public static final String HAWKBIT_USERNAME = "HAWKBIT_USERNAME"; public static final String HAWKBIT_USERNAME_DEFAULT = "hawkbit"; public static final String HAWKBIT_PASSWORD = "HAWKBIT_PASSWORD"; @@ -87,10 +86,8 @@ public class HawkbitFirmwareService implements ContainerService { protected String hawkbitRealm; protected ClientEventService clientEventService; - protected ManagerIdentityService identityService; protected AssetProcessingService assetProcessingService; protected ExecutorService executorService; - protected TimerService timerService; protected HawkbitTargetsClient targets; protected HawkbitDistributionSetsClient distributionSets; @@ -105,8 +102,8 @@ public void init(Container container) throws Exception { clientEventService = container.getService(ClientEventService.class); assetProcessingService = container.getService(AssetProcessingService.class); executorService = container.getExecutor(); - timerService = container.getService(TimerService.class); - identityService = container.getService(ManagerIdentityService.class); + TimerService timerService = container.getService(TimerService.class); + ManagerIdentityService identityService = container.getService(ManagerIdentityService.class); container.getService(ManagerWebService.class).addApiSingleton( new TargetResourceImpl(timerService, identityService, this)); @@ -196,7 +193,10 @@ public void start(Container container) throws Exception { @Override public void stop(Container container) throws Exception { - // Client lifecycle is managed by the container. + if (client != null) { + client.close(); + client = null; + } } protected void onAssetChange(AssetEvent assetEvent) { @@ -232,13 +232,13 @@ protected void handleAttributeChange(AttributeEvent attributeEvent) { } /** - * Synchronises an OpenRemote asset with a hawkBit target. + * Synchronizes an OpenRemote asset with a hawkBit target. * CREATE ensures the target exists; UPDATE recreates it if missing; DELETE removes it. */ protected void handleAssetChange(AssetEvent assetEvent) { Asset asset = assetEvent.getAsset(); - if (getFirmwareTargetInfoDescriptor(asset).isEmpty()) { + if (getFirmwareTargetInfoAttributeName(asset).isEmpty()) { return; } @@ -352,10 +352,17 @@ protected boolean isAttributeEmptyOrNull(Object value) { protected void updateFirmwareTargetMetadata(String controllerId, String key, String value) { try (Response response = targets.updateMetadata(controllerId, key, new MetadataUpdateRequest(value))) { + if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { + LOG.fine("hawkbit target not found for metadata sync targetId=" + + controllerId + ", key=" + key); + return; + } + if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { + LOG.warning("Failed to update hawkbit target metadata targetId=" + + controllerId + ", key=" + key + ", status=" + response.getStatus()); + return; + } LOG.fine("Updated hawkbit target metadata targetId=" + controllerId + ", key=" + key); - } catch (NotFoundException e) { - LOG.fine("hawkbit target not found for metadata sync targetId=" - + controllerId + ", key=" + key); } catch (Exception e) { LOG.log(Level.WARNING, "Failed to update hawkbit target metadata targetId=" + controllerId + ", key=" + key, e); @@ -364,10 +371,17 @@ protected void updateFirmwareTargetMetadata(String controllerId, String key, Str protected void deleteFirmwareTargetMetadata(String controllerId, String key) { try (Response response = targets.deleteMetadata(controllerId, key)) { + if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { + LOG.fine("hawkbit target metadata not found for delete targetId=" + + controllerId + ", key=" + key); + return; + } + if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { + LOG.warning("Failed to delete hawkbit target metadata targetId=" + + controllerId + ", key=" + key + ", status=" + response.getStatus()); + return; + } LOG.fine("Deleted hawkbit target metadata targetId=" + controllerId + ", key=" + key); - } catch (NotFoundException e) { - LOG.fine("hawkbit target metadata not found for delete targetId=" - + controllerId + ", key=" + key); } catch (Exception e) { LOG.log(Level.WARNING, "Failed to delete hawkbit target metadata targetId=" + controllerId + ", key=" + key, e); @@ -375,39 +389,35 @@ protected void deleteFirmwareTargetMetadata(String controllerId, String key) { } /** - * Finds the single attribute descriptor marked as {@code firmwareTarget} for the given asset type. + * Finds the single asset attribute marked as {@code firmwareTarget}. * Returns empty if none or more than one is found. */ - protected Optional> getFirmwareTargetInfoDescriptor(Asset asset) { - // TODO: Decide whether firmwareTarget should also be honored when defined on - // an asset attribute instance instead of only on the asset type descriptor. - Optional assetTypeInfo = ValueUtil.getAssetInfo(asset.getType()); - if (assetTypeInfo.isEmpty()) { - LOG.fine("Cannot resolve asset type info for asset type '" + asset.getType() + "'"); - return Optional.empty(); - } - - List> matchingDescriptors = assetTypeInfo.get().getAttributeDescriptors().values() - .stream() - .filter(attributeDescriptor -> attributeDescriptor.getMeta() != null - && attributeDescriptor.getMeta() - .get(FirmwareMetaItemType.FIRMWARE_TARGET) - .flatMap(metaItem -> metaItem.getValue(Boolean.class)) - .orElse(false)) + protected Optional getFirmwareTargetInfoAttributeName(Asset asset) { + List matchingAttributeNames = asset.getAttributes().values().stream() + .filter(attribute -> hasFirmwareTarget(attribute.getMeta())) + .map(Attribute::getName) + .distinct() .toList(); - if (matchingDescriptors.isEmpty()) { + if (matchingAttributeNames.isEmpty()) { return Optional.empty(); } - if (matchingDescriptors.size() > 1) { + if (matchingAttributeNames.size() > 1) { LOG.warning("Asset type '" + asset.getType() - + "' has multiple attribute descriptors with meta item '" + + "' has multiple attributes with meta item '" + FirmwareMetaItemType.FIRMWARE_TARGET.getName() + "'"); return Optional.empty(); } - return Optional.of(matchingDescriptors.getFirst()); + return Optional.of(matchingAttributeNames.getFirst()); + } + + protected boolean hasFirmwareTarget(MetaMap meta) { + return meta != null + && meta.get(FirmwareMetaItemType.FIRMWARE_TARGET) + .flatMap(metaItem -> metaItem.getValue(Boolean.class)) + .orElse(false); } protected TargetCreateRequest buildFirmwareTarget(Asset asset) { @@ -434,6 +444,15 @@ protected boolean createFirmwareTarget(TargetCreateRequest target) { protected void deleteFirmwareTarget(String controllerId) { try (Response response = targets.delete(controllerId)) { + if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { + LOG.fine("hawkbit target not found for delete id=" + controllerId); + return; + } + if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { + LOG.warning("Failed to delete hawkbit target id=" + controllerId + + ", status=" + response.getStatus()); + return; + } LOG.info("Deleted hawkbit target id=" + controllerId); } catch (Exception e) { LOG.log(Level.WARNING, "Failed to delete hawkbit target id=" + controllerId, e); @@ -446,12 +465,12 @@ protected void deleteFirmwareTarget(String controllerId) { */ protected void updateFirmwareTargetInfo(AssetEvent assetEvent) { Asset asset = assetEvent.getAsset(); - Optional> firmwareTargetInfoDescriptor = getFirmwareTargetInfoDescriptor(asset); - if (firmwareTargetInfoDescriptor.isEmpty()) { + Optional firmwareTargetInfoAttributeName = getFirmwareTargetInfoAttributeName(asset); + if (firmwareTargetInfoAttributeName.isEmpty()) { return; } - String attributeName = firmwareTargetInfoDescriptor.get().getName(); + String attributeName = firmwareTargetInfoAttributeName.get(); String controllerId = asset.getId(); switch (assetEvent.getCause()) { @@ -506,21 +525,6 @@ protected Target getFirmwareTarget(String controllerId) { } } - /** - * Uploads an artifact file to the given hawkBit software module. - */ - public Response uploadSoftwareModuleArtifact(Long softwareModuleId, InputStream inputStream, - String originalFilename, String filename) { - String effectiveFilename = TextUtil.isNullOrEmpty(filename) ? originalFilename : filename; - String uploadFilename = TextUtil.isNullOrEmpty(effectiveFilename) ? "artifact.bin" : effectiveFilename; - MultipartFormDataOutput form = new MultipartFormDataOutput(); - form.addFormData("file", inputStream, MediaType.APPLICATION_OCTET_STREAM_TYPE, uploadFilename); - return HawkbitResponseProxy.proxy("Failed to upload artifact for firmware software module '" + softwareModuleId + "'", - () -> softwareModules.uploadArtifact(softwareModuleId, - TextUtil.isNullOrEmpty(effectiveFilename) ? null : effectiveFilename, - form)); - } - /** * Returns the realm this service is bound to. Firmware endpoints are scoped to it. */ diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsClient.java index ab0c638..888942c 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitDistributionSetsClient.java @@ -39,8 +39,8 @@ public interface HawkbitDistributionSetsClient { @Consumes(APPLICATION_HAL_JSON) @Produces(APPLICATION_HAL_JSON) Response assignTargets(@PathParam("id") Long id, - @QueryParam("offline") Boolean offline, - JsonNode targets); + @QueryParam("offline") Boolean offline, + JsonNode targets); @GET @Produces(APPLICATION_JSON) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsClient.java index dca2503..e628be3 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitRolloutsClient.java @@ -51,7 +51,6 @@ Response getRollouts(@QueryParam("offset") Integer offset, @POST @Path("{id}/start") - @Produces(APPLICATION_HAL_JSON) Response start(@PathParam("id") Long id); @POST diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java index 2e3aab5..f5cf67f 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetResourceImpl.java @@ -33,7 +33,7 @@ public class DistributionSetResourceImpl extends HawkbitWebResource implements DistributionSetResource { public DistributionSetResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService, hawkbitFirmwareService); } @@ -48,8 +48,8 @@ public Response createDistributionSet(RequestParams requestParams, @Override public Response assignDistributionSet(RequestParams requestParams, String realm, Long id, - Boolean offline, - JsonNode targets) { + Boolean offline, + JsonNode targets) { requireHawkbitRealmAccess(realm); if (targets == null || !targets.isArray() || targets.isEmpty()) { throw new WebApplicationException("Assignment requires at least one target", Response.Status.BAD_REQUEST); @@ -73,9 +73,9 @@ public Response getDistributionSet(RequestParams requestParams, String realm, Lo } @Override - public void deleteDistributionSet(RequestParams requestParams, String realm, Long id) { + public Response deleteDistributionSet(RequestParams requestParams, String realm, Long id) { requireHawkbitRealmAccess(realm); - HawkbitResponseProxy.proxy("Failed to delete firmware distribution set '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to delete firmware distribution set '" + id + "'", () -> hawkbitFirmwareService.distributionSets().delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java index f20a79e..b79df60 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/DistributionSetTypeResourceImpl.java @@ -19,8 +19,8 @@ */ package org.openremote.extension.hawkbit.manager.resource; -import jakarta.ws.rs.core.Response; import com.fasterxml.jackson.databind.JsonNode; +import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; @@ -32,15 +32,15 @@ public class DistributionSetTypeResourceImpl extends HawkbitWebResource implements DistributionSetTypeResource { public DistributionSetTypeResourceImpl(TimerService timerService, - ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { + ManagerIdentityService identityService, + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService, hawkbitFirmwareService); } @Override public Response createDistributionSetType(RequestParams requestParams, String realm, - JsonNode distributionSetType) { + JsonNode distributionSetType) { requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to create firmware distribution set type", () -> hawkbitFirmwareService.distributionSetTypes().create(distributionSetType)); @@ -48,7 +48,7 @@ public Response createDistributionSetType(RequestParams requestParams, @Override public Response getDistributionSetTypes(RequestParams requestParams, String realm, Integer offset, - Integer limit) { + Integer limit) { requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware distribution set types", () -> hawkbitFirmwareService.distributionSetTypes().getDistributionSetTypes(offset, limit)); @@ -63,7 +63,7 @@ public Response getDistributionSetType(RequestParams requestParams, String realm @Override public Response getMandatoryModuleTypes(RequestParams requestParams, String realm, Long id, Integer offset, - Integer limit) { + Integer limit) { requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy( "Failed to retrieve mandatory module types for firmware distribution set type '" + id + "'", @@ -72,7 +72,7 @@ public Response getMandatoryModuleTypes(RequestParams requestParams, String real @Override public Response getOptionalModuleTypes(RequestParams requestParams, String realm, Long id, Integer offset, - Integer limit) { + Integer limit) { requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy( "Failed to retrieve optional module types for firmware distribution set type '" + id + "'", @@ -80,9 +80,9 @@ public Response getOptionalModuleTypes(RequestParams requestParams, String realm } @Override - public void deleteDistributionSetType(RequestParams requestParams, String realm, Long id) { + public Response deleteDistributionSetType(RequestParams requestParams, String realm, Long id) { requireHawkbitRealmAccess(realm); - HawkbitResponseProxy.proxy("Failed to delete firmware distribution set type '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to delete firmware distribution set type '" + id + "'", () -> hawkbitFirmwareService.distributionSetTypes().delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/HawkbitWebResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/HawkbitWebResource.java index 1f746d3..6ab0ef8 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/HawkbitWebResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/HawkbitWebResource.java @@ -31,28 +31,29 @@ /** * Base resource for hawkBit Management API proxy endpoints. *

- * The request path realm remains the OpenRemote authentication realm. The hawkBit target realm is supplied explicitly by - * each endpoint, matching manager APIs that allow superusers authenticated on {@code master} to operate on another realm. + * The request path realm remains the OpenRemote authentication realm. The hawkBit target realm defaults to the + * authenticated realm, and can be supplied explicitly by endpoints for superuser cross-realm access. */ public abstract class HawkbitWebResource extends ManagerWebResource { protected final HawkbitFirmwareService hawkbitFirmwareService; protected HawkbitWebResource(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService); this.hawkbitFirmwareService = hawkbitFirmwareService; } /** - * Verifies that the requested hawkBit realm is present, accessible to the caller, and is the realm configured for - * this hawkBit integration. + * Verifies that the requested hawkBit realm is accessible to the caller and is the realm configured for this + * hawkBit integration. If no target realm is supplied, the authenticated realm is used. * - * @param realm target OpenRemote realm for firmware management - * @throws BadRequestException if no target realm was supplied - * @throws ForbiddenException if the caller cannot access the realm, or hawkBit is not configured for that realm + * @param realm optional target OpenRemote realm for firmware management + * @throws BadRequestException if no target realm can be resolved + * @throws ForbiddenException if the caller cannot access the realm, or hawkBit is not configured for that realm */ protected void requireHawkbitRealmAccess(String realm) { + realm = realm == null || realm.isBlank() ? getAuthenticatedRealmName() : realm; if (realm == null || realm.isBlank()) { throw new BadRequestException("Firmware realm is required"); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java index d6d2947..7717de3 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/RolloutResourceImpl.java @@ -19,8 +19,8 @@ */ package org.openremote.extension.hawkbit.manager.resource; -import jakarta.ws.rs.core.Response; import com.fasterxml.jackson.databind.JsonNode; +import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; @@ -32,7 +32,7 @@ public class RolloutResourceImpl extends HawkbitWebResource implements RolloutResource { public RolloutResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService, hawkbitFirmwareService); } @@ -59,29 +59,29 @@ public Response createRollout(RequestParams requestParams, String realm, JsonNod } @Override - public void deleteRollout(RequestParams requestParams, String realm, Long id) { + public Response deleteRollout(RequestParams requestParams, String realm, Long id) { requireHawkbitRealmAccess(realm); - HawkbitResponseProxy.proxy("Failed to delete firmware rollout '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to delete firmware rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().delete(id)); } @Override - public void startRollout(RequestParams requestParams, String realm, Long id) { + public Response startRollout(RequestParams requestParams, String realm, Long id) { requireHawkbitRealmAccess(realm); - HawkbitResponseProxy.proxy("Failed to start firmware rollout '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to start firmware rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().start(id)); } @Override - public void pauseRollout(RequestParams requestParams, String realm, Long id) { + public Response pauseRollout(RequestParams requestParams, String realm, Long id) { requireHawkbitRealmAccess(realm); - HawkbitResponseProxy.proxy("Failed to pause firmware rollout '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to pause firmware rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().pause(id)); } @Override public Response getRolloutGroups(RequestParams requestParams, String realm, Long id, - Integer offset, Integer limit) { + Integer offset, Integer limit) { requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve groups for rollout '" + id + "'", () -> hawkbitFirmwareService.rollouts().getRolloutGroups(id, offset, limit, "full")); diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java index a2da4a8..0b31644 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleResourceImpl.java @@ -22,7 +22,9 @@ import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; import org.openremote.container.timer.TimerService; import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; @@ -37,14 +39,14 @@ public class SoftwareModuleResourceImpl extends HawkbitWebResource implements SoftwareModuleResource { public SoftwareModuleResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService, hawkbitFirmwareService); } @Override public Response createSoftwareModule(RequestParams requestParams, String realm, - JsonNode softwareModule) { + JsonNode softwareModule) { requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to create firmware software module", () -> hawkbitFirmwareService.softwareModules().create(softwareModule)); @@ -89,7 +91,14 @@ public Response uploadSoftwareModuleArtifact(RequestParams requestParams, String submittedFileName = filePart.getFileName().orElse(null); InputStream inputStream = filePart.getContent(InputStream.class); - return hawkbitFirmwareService.uploadSoftwareModuleArtifact(id, inputStream, submittedFileName, filename); + String effectiveFilename = filename == null || filename.isEmpty() ? submittedFileName : filename; + String uploadFilename = effectiveFilename == null || effectiveFilename.isEmpty() ? "artifact.bin" : effectiveFilename; + MultipartFormDataOutput form = new MultipartFormDataOutput(); + form.addFormData("file", inputStream, MediaType.APPLICATION_OCTET_STREAM_TYPE, uploadFilename); + return HawkbitResponseProxy.proxy("Failed to upload artifact for firmware software module '" + id + "'", + () -> hawkbitFirmwareService.softwareModules().uploadArtifact(id, + effectiveFilename == null || effectiveFilename.isEmpty() ? null : effectiveFilename, + form)); } catch (WebApplicationException e) { throw e; } catch (Exception e) { @@ -99,9 +108,9 @@ public Response uploadSoftwareModuleArtifact(RequestParams requestParams, } @Override - public void deleteSoftwareModule(RequestParams requestParams, String realm, Long id) { + public Response deleteSoftwareModule(RequestParams requestParams, String realm, Long id) { requireHawkbitRealmAccess(realm); - HawkbitResponseProxy.proxy("Failed to delete firmware software module '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to delete firmware software module '" + id + "'", () -> hawkbitFirmwareService.softwareModules().delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java index eb8500d..b64852d 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/SoftwareModuleTypeResourceImpl.java @@ -19,8 +19,8 @@ */ package org.openremote.extension.hawkbit.manager.resource; -import jakarta.ws.rs.core.Response; import com.fasterxml.jackson.databind.JsonNode; +import jakarta.ws.rs.core.Response; import org.openremote.container.timer.TimerService; import org.openremote.extension.hawkbit.manager.HawkbitFirmwareService; import org.openremote.extension.hawkbit.manager.HawkbitResponseProxy; @@ -32,14 +32,14 @@ public class SoftwareModuleTypeResourceImpl extends HawkbitWebResource implements SoftwareModuleTypeResource { public SoftwareModuleTypeResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService, hawkbitFirmwareService); } @Override public Response createSoftwareModuleType(RequestParams requestParams, String realm, - JsonNode softwareModuleType) { + JsonNode softwareModuleType) { requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to create firmware software module type", () -> hawkbitFirmwareService.softwareModuleTypes().create(softwareModuleType)); @@ -47,7 +47,7 @@ public Response createSoftwareModuleType(RequestParams requestParams, @Override public Response getSoftwareModuleTypes(RequestParams requestParams, String realm, Integer offset, - Integer limit) { + Integer limit) { requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy("Failed to retrieve firmware software module types", () -> hawkbitFirmwareService.softwareModuleTypes().getSoftwareModuleTypes(offset, limit)); @@ -61,9 +61,9 @@ public Response getSoftwareModuleType(RequestParams requestParams, String realm, } @Override - public void deleteSoftwareModuleType(RequestParams requestParams, String realm, Long id) { + public Response deleteSoftwareModuleType(RequestParams requestParams, String realm, Long id) { requireHawkbitRealmAccess(realm); - HawkbitResponseProxy.proxy("Failed to delete firmware software module type '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to delete firmware software module type '" + id + "'", () -> hawkbitFirmwareService.softwareModuleTypes().delete(id)); } } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java index e038049..fad9541 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetFilterResourceImpl.java @@ -32,7 +32,7 @@ public class TargetFilterResourceImpl extends HawkbitWebResource implements TargetFilterResource { public TargetFilterResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService, hawkbitFirmwareService); } @@ -60,9 +60,9 @@ public Response createTargetFilter(RequestParams requestParams, } @Override - public void deleteTargetFilter(RequestParams requestParams, String realm, Long id) { + public Response deleteTargetFilter(RequestParams requestParams, String realm, Long id) { requireHawkbitRealmAccess(realm); - HawkbitResponseProxy.proxy("Failed to delete firmware target filter '" + id + "'", + return HawkbitResponseProxy.proxy("Failed to delete firmware target filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().delete(id)); } @@ -76,7 +76,7 @@ public Response getAutoAssignDS(RequestParams requestParams, String realm, Long @Override public Response setAutoAssignDS(RequestParams requestParams, String realm, Long id, - JsonNode request) { + JsonNode request) { requireHawkbitRealmAccess(realm); return HawkbitResponseProxy.proxy( "Failed to set auto assign distribution set for filter '" + id + "'", @@ -84,9 +84,9 @@ public Response setAutoAssignDS(RequestParams requestParams, String realm, Long } @Override - public void deleteAutoAssignDS(RequestParams requestParams, String realm, Long id) { + public Response deleteAutoAssignDS(RequestParams requestParams, String realm, Long id) { requireHawkbitRealmAccess(realm); - HawkbitResponseProxy.proxy( + return HawkbitResponseProxy.proxy( "Failed to remove auto assign distribution set from filter '" + id + "'", () -> hawkbitFirmwareService.targetFilters().deleteAutoAssignDS(id)); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java index 4c69e21..b8cce71 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java @@ -30,7 +30,7 @@ public class TargetResourceImpl extends HawkbitWebResource implements TargetResource { public TargetResourceImpl(TimerService timerService, ManagerIdentityService identityService, - HawkbitFirmwareService hawkbitFirmwareService) { + HawkbitFirmwareService hawkbitFirmwareService) { super(timerService, identityService, hawkbitFirmwareService); } @@ -48,6 +48,13 @@ public Response getTarget(RequestParams requestParams, String realm, String id) () -> hawkbitFirmwareService.targets().get(id)); } + @Override + public Response deleteTarget(RequestParams requestParams, String realm, String id) { + requireHawkbitRealmAccess(realm); + return HawkbitResponseProxy.proxy("Failed to delete firmware target '" + id + "'", + () -> hawkbitFirmwareService.targets().delete(id)); + } + @Override public Response getMetadata(RequestParams requestParams, String realm, String id) { requireHawkbitRealmAccess(realm); @@ -85,9 +92,9 @@ public Response getAction(RequestParams requestParams, String realm, String id, } @Override - public void cancelAction(RequestParams requestParams, String realm, String id, Long actionId, Boolean force) { + public Response cancelAction(RequestParams requestParams, String realm, String id, Long actionId, Boolean force) { requireHawkbitRealmAccess(realm); - HawkbitResponseProxy.proxy( + return HawkbitResponseProxy.proxy( "Failed to cancel action '" + actionId + "' for firmware target '" + id + "'", () -> hawkbitFirmwareService.targets().cancelAction(id, actionId, force)); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java index f0cd214..1f2e250 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetResource.java @@ -39,7 +39,9 @@ @Path("firmware/distributionset") public interface DistributionSetResource { - /** Create a distribution set. Body is a hawkBit DistributionSet create payload. */ + /** + * Create a distribution set. Body is a hawkBit DistributionSet create payload. + */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @@ -68,25 +70,31 @@ Response assignDistributionSet(@BeanParam RequestParams requestParams, @QueryParam("offline") Boolean offline, JsonNode targets); - /** Retrieve all distribution sets, paged. */ + /** + * Retrieve all distribution sets, paged. + */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getDistributionSets(@BeanParam RequestParams requestParams, - @QueryParam("realm") String realm, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("realm") String realm, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); - /** Retrieve a single distribution set by id. */ + /** + * Retrieve a single distribution set by id. + */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getDistributionSet(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); - /** Delete a distribution set. */ + /** + * Delete a distribution set. + */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void deleteDistributionSet(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); + Response deleteDistributionSet(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java index a0ba350..92ef77f 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/DistributionSetTypeResource.java @@ -39,32 +39,38 @@ @Path("firmware/distributionsettype") public interface DistributionSetTypeResource { - /** Create a distribution-set type. Body is a hawkBit DistributionSetType create payload. */ + /** + * Create a distribution-set type. Body is a hawkBit DistributionSetType create payload. + */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createDistributionSetType(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - JsonNode distributionSetType); + JsonNode distributionSetType); - /** Retrieve all distribution-set types, paged. */ + /** + * Retrieve all distribution-set types, paged. + */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getDistributionSetTypes(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); - /** Retrieve a single distribution-set type by id. */ + /** + * Retrieve a single distribution-set type by id. + */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getDistributionSetType(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @PathParam("id") Long id); + @PathParam("id") Long id); /** * Retrieve the module types every DS of this type must include. @@ -78,9 +84,9 @@ Response getDistributionSetType(@BeanParam RequestParams requestParams, @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getMandatoryModuleTypes(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); /** * Retrieve the module types that a DS of this type may optionally include. @@ -94,13 +100,15 @@ Response getMandatoryModuleTypes(@BeanParam RequestParams requestParams, @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getOptionalModuleTypes(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); - /** Delete a distribution-set type. */ + /** + * Delete a distribution-set type. + */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void deleteDistributionSetType(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); + Response deleteDistributionSetType(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java index 3bb0f93..4e1b19e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/RolloutResource.java @@ -51,50 +51,60 @@ public interface RolloutResource { @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getRollouts(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); - /** Retrieve a single rollout by id. */ + /** + * Retrieve a single rollout by id. + */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getRollout(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @PathParam("id") Long id); + @PathParam("id") Long id); - /** Create a rollout. Body matches hawkBit's Rollout create payload. */ + /** + * Create a rollout. Body matches hawkBit's Rollout create payload. + */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createRollout(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - JsonNode rollout); + JsonNode rollout); - /** Delete a rollout. */ + /** + * Delete a rollout. + */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void deleteRollout(@BeanParam RequestParams requestParams, - @QueryParam("realm") String realm, - @PathParam("id") Long id); + Response deleteRollout(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, + @PathParam("id") Long id); - /** Start a rollout. */ + /** + * Start a rollout. + */ @POST @Path("{id}/start") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void startRollout(@BeanParam RequestParams requestParams, - @QueryParam("realm") String realm, - @PathParam("id") Long id); + Response startRollout(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, + @PathParam("id") Long id); - /** Pause a running rollout. */ + /** + * Pause a running rollout. + */ @POST @Path("{id}/pause") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void pauseRollout(@BeanParam RequestParams requestParams, - @QueryParam("realm") String realm, - @PathParam("id") Long id); + Response pauseRollout(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, + @PathParam("id") Long id); /** * Retrieve deployment groups for a rollout, paged. @@ -107,17 +117,19 @@ void pauseRollout(@BeanParam RequestParams requestParams, @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getRolloutGroups(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @PathParam("id") Long id, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @PathParam("id") Long id, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); - /** Retrieve a single deployment group within a rollout. */ + /** + * Retrieve a single deployment group within a rollout. + */ @GET @Path("{id}/deploygroups/{groupId}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getRolloutGroup(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @PathParam("id") Long id, - @PathParam("groupId") Long groupId); + @PathParam("id") Long id, + @PathParam("groupId") Long groupId); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java index 6de84c4..fa368c9 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleResource.java @@ -43,32 +43,40 @@ @Path("firmware/softwaremodule") public interface SoftwareModuleResource { - /** Create a software module. Body matches hawkBit's SoftwareModule create payload. */ + /** + * Create a software module. Body matches hawkBit's SoftwareModule create payload. + */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createSoftwareModule(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - JsonNode softwareModule); + JsonNode softwareModule); - /** Retrieve all software modules, paged. */ + /** + * Retrieve all software modules, paged. + */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getSoftwareModules(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); - /** Retrieve a single software module by id. */ + /** + * Retrieve a single software module by id. + */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getSoftwareModule(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); - /** Retrieve all artifacts attached to a software module. */ + /** + * Retrieve all artifacts attached to a software module. + */ @GET @Path("{id}/artifacts") @Produces(APPLICATION_JSON) @@ -90,14 +98,16 @@ Response getSoftwareModules(@BeanParam RequestParams requestParams, @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response uploadSoftwareModuleArtifact(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @PathParam("id") Long id, - @QueryParam("filename") String filename, - List parts); + @PathParam("id") Long id, + @QueryParam("filename") String filename, + List parts); - /** Delete a software module. */ + /** + * Delete a software module. + */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void deleteSoftwareModule(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); + Response deleteSoftwareModule(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java index 7b8a2bb..6ff0aa2 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/SoftwareModuleTypeResource.java @@ -39,36 +39,44 @@ @Path("firmware/softwaremoduletype") public interface SoftwareModuleTypeResource { - /** Create a software-module type. Body matches hawkBit's SoftwareModuleType create payload. */ + /** + * Create a software-module type. Body matches hawkBit's SoftwareModuleType create payload. + */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createSoftwareModuleType(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - JsonNode softwareModuleType); + JsonNode softwareModuleType); - /** Retrieve all software-module types, paged. */ + /** + * Retrieve all software-module types, paged. + */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getSoftwareModuleTypes(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); - /** Retrieve a single software-module type by id. */ + /** + * Retrieve a single software-module type by id. + */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getSoftwareModuleType(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @PathParam("id") Long id); + @PathParam("id") Long id); - /** Delete a software-module type. */ + /** + * Delete a software-module type. + */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void deleteSoftwareModuleType(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); + Response deleteSoftwareModuleType(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java index c722914..50142d3 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetFilterResource.java @@ -39,16 +39,20 @@ @Path("firmware/targetfilter") public interface TargetFilterResource { - /** Retrieve all target filter queries, paged. */ + /** + * Retrieve all target filter queries, paged. + */ @GET @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getTargetFilters(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @QueryParam("offset") Integer offset, - @QueryParam("limit") Integer limit); + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); - /** Retrieve a single target filter query by id. */ + /** + * Retrieve a single target filter query by id. + */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @@ -57,31 +61,37 @@ Response getTargetFilter(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") Long id); - /** Create a target filter query. Body matches hawkBit's TargetFilterQuery create payload. */ + /** + * Create a target filter query. Body matches hawkBit's TargetFilterQuery create payload. + */ @POST @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response createTargetFilter(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - JsonNode filter); + JsonNode filter); - /** Delete a target filter query. */ + /** + * Delete a target filter query. + */ @DELETE @Path("{id}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void deleteTargetFilter(@BeanParam RequestParams requestParams, - @QueryParam("realm") String realm, - @PathParam("id") Long id); + Response deleteTargetFilter(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, + @PathParam("id") Long id); - /** Retrieve the auto-assign distribution set configured for a target filter. */ + /** + * Retrieve the auto-assign distribution set configured for a target filter. + */ @GET @Path("{id}/autoAssignDS") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getAutoAssignDS(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @PathParam("id") Long id); + @PathParam("id") Long id); /** * Configure the auto-assign distribution set for a target filter. @@ -96,14 +106,16 @@ Response getAutoAssignDS(@BeanParam RequestParams requestParams, @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) Response setAutoAssignDS(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, - @PathParam("id") Long id, - JsonNode request); + @PathParam("id") Long id, + JsonNode request); - /** Remove the auto-assign distribution set from a target filter. */ + /** + * Remove the auto-assign distribution set from a target filter. + */ @DELETE @Path("{id}/autoAssignDS") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void deleteAutoAssignDS(@BeanParam RequestParams requestParams, - @QueryParam("realm") String realm, - @PathParam("id") Long id); + Response deleteAutoAssignDS(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, + @PathParam("id") Long id); } diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java index f64d224..5346d49 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java @@ -52,14 +52,26 @@ Response getTargets(@BeanParam RequestParams requestParams, @QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit); - /** Retrieve a single firmware target by controllerId. */ + /** + * Retrieve a single firmware target by controllerId. + */ @GET @Path("{id}") @Produces(APPLICATION_JSON) @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getTarget(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") String id); - /** Retrieve all metadata key/value pairs for a firmware target. */ + /** + * Delete a firmware target by controllerId. + */ + @DELETE + @Path("{id}") + @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) + Response deleteTarget(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") String id); + + /** + * Retrieve all metadata key/value pairs for a firmware target. + */ @GET @Path("{id}/metadata") @Produces(APPLICATION_JSON) @@ -90,7 +102,9 @@ Response getTargets(@BeanParam RequestParams requestParams, @RolesAllowed({Constants.READ_ADMIN_ROLE}) Response getInstalledDs(@BeanParam RequestParams requestParams, @QueryParam("realm") String realm, @PathParam("id") String id); - /** Retrieve the action history for a firmware target, paged. */ + /** + * Retrieve the action history for a firmware target, paged. + */ @GET @Path("{id}/actions") @Produces(APPLICATION_JSON) @@ -101,7 +115,9 @@ Response getActions(@BeanParam RequestParams requestParams, @QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit); - /** Retrieve a single action for a firmware target. */ + /** + * Retrieve a single action for a firmware target. + */ @GET @Path("{id}/actions/{actionId}") @Produces(APPLICATION_JSON) @@ -120,9 +136,9 @@ Response getAction(@BeanParam RequestParams requestParams, @DELETE @Path("{id}/actions/{actionId}") @RolesAllowed({Constants.WRITE_ADMIN_ROLE}) - void cancelAction(@BeanParam RequestParams requestParams, - @QueryParam("realm") String realm, - @PathParam("id") String id, - @PathParam("actionId") Long actionId, - @QueryParam("force") Boolean force); + Response cancelAction(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, + @PathParam("id") String id, + @PathParam("actionId") Long actionId, + @QueryParam("force") Boolean force); } diff --git a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy index 62b06bb..5623cfc 100644 --- a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy +++ b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy @@ -26,11 +26,7 @@ import org.openremote.extension.hawkbit.model.hawkbit.MetadataUpdateRequest import org.openremote.extension.hawkbit.model.hawkbit.Target import org.openremote.model.asset.Asset import org.openremote.model.asset.AssetEvent -import org.openremote.model.attribute.AttributeEvent -import org.openremote.model.attribute.AttributeMap -import org.openremote.model.attribute.MetaItem -import org.openremote.model.attribute.MetaMap -import org.openremote.model.value.AttributeDescriptor +import org.openremote.model.attribute.* import org.openremote.test.ManagerContainerTrait import spock.lang.Specification @@ -45,11 +41,28 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain * with any asset type. */ static class TestableHawkbitFirmwareService extends HawkbitFirmwareService { - protected Optional> getFirmwareTargetInfoDescriptor(Asset asset) { - return Optional.of(new AttributeDescriptor<>("firmwareTarget", TEXT)) + protected Optional getFirmwareTargetInfoAttributeName(Asset asset) { + return Optional.of("firmwareTarget") } } + def "getFirmwareTargetInfoAttributeName rejects multiple marked attributes"() { + given: "an asset with multiple attributes marked as firmware target" + def service = new HawkbitFirmwareService() + def meta = new MetaMap() + meta.put(new MetaItem<>(FirmwareMetaItemType.FIRMWARE_TARGET, true)) + + def asset = Mock(Asset) + asset.getType() >> "unknown:asset:type" + asset.getAttributes() >> new AttributeMap([ + new Attribute<>("firmwareTargetInfo", TEXT).setMeta(meta), + new Attribute<>("otherFirmwareTargetInfo", TEXT).setMeta(meta) + ]) + + expect: "ambiguous firmware target info attributes are ignored" + service.getFirmwareTargetInfoAttributeName(asset) == Optional.empty() + } + def "handleAssetChange with CREATE cause creates target when it does not exist"() { given: "a service with mocked targets client" def service = new TestableHawkbitFirmwareService() From 64a64c4b48c74c93fc8ad2825142d89051b09d58 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Wed, 20 May 2026 14:18:11 +0200 Subject: [PATCH 14/18] Return target on create, remove unnecessary getTarget calls. --- .../manager/HawkbitFirmwareService.java | 75 ++++++++----------- .../manager/HawkbitFirmwareServiceTest.groovy | 42 ++++++++--- 2 files changed, 62 insertions(+), 55 deletions(-) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java index 6791744..978545d 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java @@ -237,13 +237,15 @@ protected void handleAttributeChange(AttributeEvent attributeEvent) { */ protected void handleAssetChange(AssetEvent assetEvent) { Asset asset = assetEvent.getAsset(); + Optional firmwareTargetInfoAttributeName = getFirmwareTargetInfoAttributeName(asset); - if (getFirmwareTargetInfoAttributeName(asset).isEmpty()) { + if (firmwareTargetInfoAttributeName.isEmpty()) { return; } + String attributeName = firmwareTargetInfoAttributeName.get(); String controllerId = asset.getId(); - boolean shouldUpdateFirmwareTargetInfo = false; + Target firmwareTarget = null; LOG.fine("Processing hawkbit target sync cause=" + assetEvent.getCause() + ", assetId=" + asset.getId() + ", assetType=" + asset.getType() @@ -251,30 +253,25 @@ protected void handleAssetChange(AssetEvent assetEvent) { switch (assetEvent.getCause()) { case CREATE: - LOG.info("Creating hawkbit target for asset id=" + asset.getId()); - shouldUpdateFirmwareTargetInfo = createFirmwareTarget(buildFirmwareTarget(asset)); - break; case UPDATE: - LOG.fine("Checking hawkbit target for update asset id=" + asset.getId()); + LOG.fine("Ensuring hawkbit target exists asset id=" + asset.getId()); Target existingTarget; try { existingTarget = getFirmwareTarget(controllerId); } catch (Exception e) { LOG.log(Level.WARNING, "Failed to query hawkbit target id=" + controllerId - + ", skipping update to avoid spurious create", e); + + ", skipping sync to avoid spurious create", e); break; } if (existingTarget != null) { LOG.fine("hawkbit target already exists id=" + controllerId); - shouldUpdateFirmwareTargetInfo = true; + firmwareTarget = existingTarget; break; } LOG.info("hawkbit target missing for asset id=" + asset.getId() + ", creating it now"); - if (createFirmwareTarget(buildFirmwareTarget(asset))) { - shouldUpdateFirmwareTargetInfo = true; - } + firmwareTarget = createFirmwareTarget(buildFirmwareTarget(asset)); break; case DELETE: deleteFirmwareTarget(controllerId); @@ -283,13 +280,13 @@ protected void handleAssetChange(AssetEvent assetEvent) { break; } - if (shouldUpdateFirmwareTargetInfo) { - updateFirmwareTargetInfo(assetEvent); + if (firmwareTarget != null) { + updateFirmwareTargetInfo(assetEvent, attributeName, firmwareTarget); updateFirmwareTargetMetadata(asset); } } - protected void updateFirmwareTargetMetadata(Asset asset) { + public void updateFirmwareTargetMetadata(Asset asset) { String controllerId = asset.getId(); for (Attribute attribute : asset.getAttributes().values()) { if (!hasFirmwareMetadata(asset.getType(), attribute.getName(), attribute.getMeta())) { @@ -304,7 +301,7 @@ protected void updateFirmwareTargetMetadata(Asset asset) { * Checks whether an attribute (by instance meta or type descriptor meta) is marked * as firmware metadata. */ - protected boolean hasFirmwareMetadata(String assetType, String attributeName, MetaMap meta) { + public boolean hasFirmwareMetadata(String assetType, String attributeName, MetaMap meta) { if (hasFirmwareMetadata(meta)) { return true; } @@ -321,14 +318,14 @@ protected boolean hasFirmwareMetadata(String assetType, String attributeName, Me .orElse(false); } - protected boolean hasFirmwareMetadata(MetaMap meta) { + public boolean hasFirmwareMetadata(MetaMap meta) { return meta != null && meta.get(FirmwareMetaItemType.FIRMWARE_METADATA) .flatMap(metaItem -> metaItem.getValue(Boolean.class)) .orElse(false); } - protected void syncFirmwareTargetMetadataValue(String controllerId, String key, Object value) { + public void syncFirmwareTargetMetadataValue(String controllerId, String key, Object value) { if (isAttributeEmptyOrNull(value)) { deleteFirmwareTargetMetadata(controllerId, key); return; @@ -350,7 +347,7 @@ protected boolean isAttributeEmptyOrNull(Object value) { .orElse(false); } - protected void updateFirmwareTargetMetadata(String controllerId, String key, String value) { + public void updateFirmwareTargetMetadata(String controllerId, String key, String value) { try (Response response = targets.updateMetadata(controllerId, key, new MetadataUpdateRequest(value))) { if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { LOG.fine("hawkbit target not found for metadata sync targetId=" @@ -369,7 +366,7 @@ protected void updateFirmwareTargetMetadata(String controllerId, String key, Str } } - protected void deleteFirmwareTargetMetadata(String controllerId, String key) { + public void deleteFirmwareTargetMetadata(String controllerId, String key) { try (Response response = targets.deleteMetadata(controllerId, key)) { if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { LOG.fine("hawkbit target metadata not found for delete targetId=" @@ -392,7 +389,7 @@ protected void deleteFirmwareTargetMetadata(String controllerId, String key) { * Finds the single asset attribute marked as {@code firmwareTarget}. * Returns empty if none or more than one is found. */ - protected Optional getFirmwareTargetInfoAttributeName(Asset asset) { + public Optional getFirmwareTargetInfoAttributeName(Asset asset) { List matchingAttributeNames = asset.getAttributes().values().stream() .filter(attribute -> hasFirmwareTarget(attribute.getMeta())) .map(Attribute::getName) @@ -413,36 +410,41 @@ protected Optional getFirmwareTargetInfoAttributeName(Asset asset) { return Optional.of(matchingAttributeNames.getFirst()); } - protected boolean hasFirmwareTarget(MetaMap meta) { + public boolean hasFirmwareTarget(MetaMap meta) { return meta != null && meta.get(FirmwareMetaItemType.FIRMWARE_TARGET) .flatMap(metaItem -> metaItem.getValue(Boolean.class)) .orElse(false); } - protected TargetCreateRequest buildFirmwareTarget(Asset asset) { + public TargetCreateRequest buildFirmwareTarget(Asset asset) { String controllerId = asset.getId(); String targetName = asset.getAssetType() + "-" + controllerId; String targetDescription = "assetId=" + asset.getId() + "; realm=" + asset.getRealm(); return new TargetCreateRequest(controllerId, targetName, targetDescription); } - protected boolean createFirmwareTarget(TargetCreateRequest target) { + public Target createFirmwareTarget(TargetCreateRequest target) { LOG.info("Creating hawkbit target id=" + target.controllerId()); try (Response response = targets.create(new TargetCreateRequest[]{target})) { - boolean created = response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL; - if (!created) { + if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { LOG.warning("Failed to create hawkbit target id=" + target.controllerId() + ", status=" + response.getStatus()); + return null; } - return created; + Target[] created = response.readEntity(Target[].class); + if (created == null || created.length == 0) { + LOG.warning("hawkbit create returned no targets id=" + target.controllerId()); + return null; + } + return created[0]; } catch (Exception e) { LOG.log(Level.WARNING, "Failed to create hawkbit target id=" + target.controllerId(), e); - return false; + return null; } } - protected void deleteFirmwareTarget(String controllerId) { + public void deleteFirmwareTarget(String controllerId) { try (Response response = targets.delete(controllerId)) { if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { LOG.fine("hawkbit target not found for delete id=" + controllerId); @@ -463,24 +465,13 @@ protected void deleteFirmwareTarget(String controllerId) { * Builds a JSON value containing the hawkBit target's controllerId and securityToken, * then sends it as an attribute event if the value has changed. */ - protected void updateFirmwareTargetInfo(AssetEvent assetEvent) { + protected void updateFirmwareTargetInfo(AssetEvent assetEvent, String attributeName, Target firmwareTarget) { Asset asset = assetEvent.getAsset(); - Optional firmwareTargetInfoAttributeName = getFirmwareTargetInfoAttributeName(asset); - if (firmwareTargetInfoAttributeName.isEmpty()) { - return; - } - - String attributeName = firmwareTargetInfoAttributeName.get(); - String controllerId = asset.getId(); switch (assetEvent.getCause()) { case CREATE: case UPDATE: try { - Target firmwareTarget = getFirmwareTarget(controllerId); - if (firmwareTarget == null) { - return; - } Map firmwareTargetInfo = new LinkedHashMap<>(); firmwareTargetInfo.put("controllerId", firmwareTarget.controllerId()); firmwareTargetInfo.put("securityToken", firmwareTarget.securityToken()); @@ -497,8 +488,6 @@ protected void updateFirmwareTargetInfo(AssetEvent assetEvent) { assetProcessingService.sendAttributeEvent( new AttributeEvent(asset.getId(), attributeName, newValueJson), getClass().getSimpleName()); - LOG.info("Updated firmware target info attribute for asset id=" + asset.getId() - + ", controllerId=" + firmwareTarget.controllerId()); } catch (Exception e) { LOG.log(Level.WARNING, "Failed to update firmware target info for asset id=" + asset.getId(), e); } @@ -512,7 +501,7 @@ protected void updateFirmwareTargetInfo(AssetEvent assetEvent) { * Queries hawkBit for a target by controllerId. * Returns {@code null} if the target is not found (404). */ - protected Target getFirmwareTarget(String controllerId) { + public Target getFirmwareTarget(String controllerId) { try (Response response = targets.get(controllerId)) { if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { return null; diff --git a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy index 5623cfc..36ef2dc 100644 --- a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy +++ b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy @@ -41,7 +41,7 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain * with any asset type. */ static class TestableHawkbitFirmwareService extends HawkbitFirmwareService { - protected Optional getFirmwareTargetInfoAttributeName(Asset asset) { + Optional getFirmwareTargetInfoAttributeName(Asset asset) { return Optional.of("firmwareTarget") } } @@ -67,6 +67,7 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain given: "a service with mocked targets client" def service = new TestableHawkbitFirmwareService() service.targets = Mock(HawkbitTargetsClient) + def createdTarget = new Target(CONTROLLER_ID, null, null, "token", null, null, null, null, null, null, null, null, null) def asset = Mock(Asset) asset.getId() >> CONTROLLER_ID asset.getRealm() >> "master" @@ -75,9 +76,28 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain when: "handling an asset CREATE event" service.handleAssetChange(new AssetEvent(AssetEvent.Cause.CREATE, asset)) - then: "hawkBit creates the target and then queries it to update target info" - 1 * service.targets.create(_) >> Response.ok().build() - 1 * service.targets.get(CONTROLLER_ID) >> Response.ok(new Target(CONTROLLER_ID, null, null, "token", null, null, null, null, null, null, null, null, null)).build() + then: "hawkBit checks (404), creates, then uses the created target to update target info" + 1 * service.targets.get(CONTROLLER_ID) >> Response.status(Response.Status.NOT_FOUND).build() + 1 * service.targets.create(_) >> Response.ok(new Target[]{createdTarget}).build() + } + + def "handleAssetChange with CREATE cause skips create when target already exists"() { + given: "a service with mocked targets client returning an existing target" + def service = new TestableHawkbitFirmwareService() + def existingTarget = new Target(CONTROLLER_ID, null, null, "token", null, null, null, null, null, null, null, null, null) + service.targets = Mock(HawkbitTargetsClient) + + def asset = Mock(Asset) + asset.getId() >> CONTROLLER_ID + asset.getRealm() >> "master" + asset.getAttributes() >> new AttributeMap() + + when: "handling an asset CREATE event for an already-existing target" + service.handleAssetChange(new AssetEvent(AssetEvent.Cause.CREATE, asset)) + + then: "hawkBit is queried but create is not called" + 1 * service.targets.get(CONTROLLER_ID) >> Response.ok(existingTarget).build() + 0 * service.targets.create(_) } def "handleAssetChange with UPDATE cause skips create when target already exists"() { @@ -95,14 +115,15 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain service.handleAssetChange(new AssetEvent(AssetEvent.Cause.UPDATE, asset)) then: "hawkBit is queried but create is not called" - 2 * service.targets.get(CONTROLLER_ID) >> Response.ok(existingTarget).build() + 1 * service.targets.get(CONTROLLER_ID) >> Response.ok(existingTarget).build() 0 * service.targets.create(_) } def "handleAssetChange with UPDATE cause creates target when it is missing"() { - given: "a service with mocked targets client returning 404 then the created target" + given: "a service with mocked targets client returning 404 then creating the target" def service = new TestableHawkbitFirmwareService() service.targets = Mock(HawkbitTargetsClient) + def createdTarget = new Target(CONTROLLER_ID, null, null, "token", null, null, null, null, null, null, null, null, null) def asset = Mock(Asset) asset.getId() >> CONTROLLER_ID @@ -112,12 +133,9 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain when: "handling an asset UPDATE event for a missing target" service.handleAssetChange(new AssetEvent(AssetEvent.Cause.UPDATE, asset)) - then: "hawkBit queries (404), creates, then queries again for info update" - 2 * service.targets.get(CONTROLLER_ID) >>> [ - Response.status(Response.Status.NOT_FOUND).build(), - Response.ok(new Target(CONTROLLER_ID, null, null, "token", null, null, null, null, null, null, null, null, null)).build() - ] - 1 * service.targets.create(_) >> Response.ok().build() + then: "hawkBit queries (404), creates, then uses the created target for info update" + 1 * service.targets.get(CONTROLLER_ID) >> Response.status(Response.Status.NOT_FOUND).build() + 1 * service.targets.create(_) >> Response.ok(new Target[]{createdTarget}).build() } def "handleAssetChange with UPDATE cause logs warning when getFirmwareTarget throws exception"() { From 60e757bbde6403477ff7e27bce0c0962fd8521b1 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Wed, 20 May 2026 15:37:31 +0200 Subject: [PATCH 15/18] Allow providing a custom securityToken when creating a hawkBit target + method renames. --- .../manager/HawkbitFirmwareService.java | 327 +++++++++--------- .../hawkbit/model/FirmwareMetaItemType.java | 1 - .../model/hawkbit/TargetCreateRequest.java | 4 +- .../manager/HawkbitFirmwareServiceTest.groovy | 40 ++- 4 files changed, 199 insertions(+), 173 deletions(-) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java index 978545d..efd7297 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java @@ -63,6 +63,10 @@ import static org.openremote.model.syslog.SyslogCategory.API; import static org.openremote.model.util.MapAccess.getString; +/** + * Connects the manager to the hawkBit Management API and keeps OpenRemote assets + * marked for firmware management synchronized with hawkBit targets and metadata. + */ public class HawkbitFirmwareService implements ContainerService { /** * hawkBit integration is currently limited to a single realm, @@ -121,9 +125,6 @@ public void init(Container container) throws Exception { new TargetFilterResourceImpl(timerService, identityService, this)); } - /** - * Builds the hawkBit REST client and subscribes to asset/attribute events. - */ @Override public void start(Container container) throws Exception { String hawkbitURI = getString(container.getConfig(), HAWKBIT_MANAGEMENT_API_URL, @@ -134,7 +135,7 @@ public void start(Container container) throws Exception { } if (HAWKBIT_MANAGEMENT_API_URL_DEFAULT.equals(hawkbitURI)) { - LOG.info(HAWKBIT_MANAGEMENT_API_URL + " not configured, using default=" + LOG.fine(HAWKBIT_MANAGEMENT_API_URL + " not configured, using default=" + HAWKBIT_MANAGEMENT_API_URL_DEFAULT); } @@ -143,7 +144,7 @@ public void start(Container container) throws Exception { try { uri = new URI(hawkbitURI); } catch (URISyntaxException e) { - LOG.log(Level.SEVERE, HAWKBIT_MANAGEMENT_API_URL + " value is not a valid URI", e); + LOG.log(Level.SEVERE, "Invalid " + HAWKBIT_MANAGEMENT_API_URL + " value", e); throw e; } @@ -152,8 +153,6 @@ public void start(Container container) throws Exception { hawkbitRealm = getString(container.getConfig(), HAWKBIT_REALM, HAWKBIT_REALM_DEFAULT); - LOG.info(HAWKBIT_MANAGEMENT_API_URL + "=" + uri); - client = createClient(org.openremote.container.Container.EXECUTOR, CONNECTION_POOL_SIZE, CONNECTION_TIMEOUT_MILLISECONDS, resteasyClientBuilder -> { WebClient.registerDefaults(resteasyClientBuilder); @@ -187,8 +186,7 @@ public void start(Container container) throws Exception { null, this::onAttributeChange); - LOG.log(Level.INFO, - "Firmware Service started, connected hawkBit instance: " + uri + ", for realm: " + hawkbitRealm); + LOG.info("Started hawkBit firmware service uri=" + uri + ", realm=" + hawkbitRealm); } @Override @@ -216,284 +214,226 @@ protected void onAttributeChange(AttributeEvent attributeEvent) { } protected void handleAttributeChange(AttributeEvent attributeEvent) { - if (!hasFirmwareMetadata(attributeEvent.getAssetType(), attributeEvent.getName(), attributeEvent.getMeta())) { + if (!hasMetadataFlag(attributeEvent.getAssetType(), attributeEvent.getName(), attributeEvent.getMeta())) { return; } if (attributeEvent.isDeleted()) { - deleteFirmwareTargetMetadata(attributeEvent.getId(), attributeEvent.getName()); + deleteTargetMetadata(attributeEvent.getId(), attributeEvent.getName()); return; } - syncFirmwareTargetMetadataValue( + syncTargetMetadataValue( attributeEvent.getId(), attributeEvent.getName(), attributeEvent.getValue().orElse(null)); } - /** - * Synchronizes an OpenRemote asset with a hawkBit target. - * CREATE ensures the target exists; UPDATE recreates it if missing; DELETE removes it. - */ + protected void handleAssetChange(AssetEvent assetEvent) { Asset asset = assetEvent.getAsset(); - Optional firmwareTargetInfoAttributeName = getFirmwareTargetInfoAttributeName(asset); + Optional targetInfoAttributeName = getTargetInfoAttributeName(asset); - if (firmwareTargetInfoAttributeName.isEmpty()) { + if (targetInfoAttributeName.isEmpty()) { return; } - String attributeName = firmwareTargetInfoAttributeName.get(); + String attributeName = targetInfoAttributeName.get(); String controllerId = asset.getId(); - Target firmwareTarget = null; + Target target = null; - LOG.fine("Processing hawkbit target sync cause=" + assetEvent.getCause() - + ", assetId=" + asset.getId() + ", assetType=" + asset.getType() - + ", controllerId=" + controllerId); + LOG.fine("Processing hawkBit target sync cause=" + assetEvent.getCause() + + ", assetId=" + asset.getId()); switch (assetEvent.getCause()) { case CREATE: case UPDATE: - LOG.fine("Ensuring hawkbit target exists asset id=" + asset.getId()); Target existingTarget; try { - existingTarget = getFirmwareTarget(controllerId); + existingTarget = getTarget(controllerId); } catch (Exception e) { - LOG.log(Level.WARNING, "Failed to query hawkbit target id=" + controllerId - + ", skipping sync to avoid spurious create", e); + LOG.log(Level.WARNING, "hawkBit target lookup failed id=" + controllerId + ", skipping sync", e); break; } if (existingTarget != null) { - LOG.fine("hawkbit target already exists id=" + controllerId); - firmwareTarget = existingTarget; + LOG.fine("hawkBit target exists id=" + controllerId); + target = existingTarget; break; } - LOG.info("hawkbit target missing for asset id=" + asset.getId() + ", creating it now"); - firmwareTarget = createFirmwareTarget(buildFirmwareTarget(asset)); + LOG.fine("hawkBit target missing id=" + controllerId + ", creating"); + target = createTarget(asset); break; case DELETE: - deleteFirmwareTarget(controllerId); - break; - default: + deleteTarget(controllerId); break; } - if (firmwareTarget != null) { - updateFirmwareTargetInfo(assetEvent, attributeName, firmwareTarget); - updateFirmwareTargetMetadata(asset); + if (target != null) { + updateTargetInfoForAttribute(asset, attributeName, target); + syncTargetMetadata(asset); } } - public void updateFirmwareTargetMetadata(Asset asset) { + /** + * Synchronizes all asset attributes marked as firmware metadata to the hawkBit target. + */ + public void syncTargetMetadata(Asset asset) { String controllerId = asset.getId(); for (Attribute attribute : asset.getAttributes().values()) { - if (!hasFirmwareMetadata(asset.getType(), attribute.getName(), attribute.getMeta())) { + if (!hasMetadataFlag(asset.getType(), attribute.getName(), attribute.getMeta())) { continue; } - syncFirmwareTargetMetadataValue(controllerId, attribute.getName(), attribute.getValue().orElse(null)); + syncTargetMetadataValue(controllerId, attribute.getName(), attribute.getValue().orElse(null)); } } /** - * Checks whether an attribute (by instance meta or type descriptor meta) is marked - * as firmware metadata. + * Synchronizes a single metadata value to the hawkBit target. + * Deletes the metadata entry when the value is empty or {@code null}. */ - public boolean hasFirmwareMetadata(String assetType, String attributeName, MetaMap meta) { - if (hasFirmwareMetadata(meta)) { - return true; - } - - if (assetType == null) { - return false; - } - - Optional assetTypeInfo = ValueUtil.getAssetInfo(assetType); - return assetTypeInfo - .map(typeInfo -> typeInfo.getAttributeDescriptors().values().stream() - .filter(attributeDescriptor -> Objects.equals(attributeDescriptor.getName(), attributeName)) - .anyMatch(attributeDescriptor -> hasFirmwareMetadata(attributeDescriptor.getMeta()))) - .orElse(false); - } - - public boolean hasFirmwareMetadata(MetaMap meta) { - return meta != null - && meta.get(FirmwareMetaItemType.FIRMWARE_METADATA) - .flatMap(metaItem -> metaItem.getValue(Boolean.class)) - .orElse(false); - } - - public void syncFirmwareTargetMetadataValue(String controllerId, String key, Object value) { - if (isAttributeEmptyOrNull(value)) { - deleteFirmwareTargetMetadata(controllerId, key); + public void syncTargetMetadataValue(String controllerId, String key, Object value) { + if (isEmptyAttributeValue(value)) { + deleteTargetMetadata(controllerId, key); return; } Optional metadataValue = ValueUtil.getStringCoerced(value); if (metadataValue.isEmpty()) { - LOG.warning("Cannot convert firmware metadata value to string for target id=" - + controllerId + ", key=" + key); + LOG.warning("Cannot sync hawkBit metadata id=" + controllerId + + ", key=" + key + ": value is not string-compatible"); return; } - updateFirmwareTargetMetadata(controllerId, key, metadataValue.get()); + updateTargetMetadata(controllerId, key, metadataValue.get()); } - protected boolean isAttributeEmptyOrNull(Object value) { - return value == null || ValueUtil.getStringCoerced(value) - .map(String::isEmpty) - .orElse(false); - } - - public void updateFirmwareTargetMetadata(String controllerId, String key, String value) { + /** + * Updates a single hawkBit target metadata entry. + */ + public void updateTargetMetadata(String controllerId, String key, String value) { try (Response response = targets.updateMetadata(controllerId, key, new MetadataUpdateRequest(value))) { if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { - LOG.fine("hawkbit target not found for metadata sync targetId=" + LOG.fine("hawkBit target not found for metadata sync id=" + controllerId + ", key=" + key); return; } if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { - LOG.warning("Failed to update hawkbit target metadata targetId=" + LOG.warning("Failed to update hawkBit metadata id=" + controllerId + ", key=" + key + ", status=" + response.getStatus()); return; } - LOG.fine("Updated hawkbit target metadata targetId=" + controllerId + ", key=" + key); + LOG.fine("Updated hawkBit metadata id=" + controllerId + ", key=" + key); } catch (Exception e) { - LOG.log(Level.WARNING, "Failed to update hawkbit target metadata targetId=" + LOG.log(Level.WARNING, "Failed to update hawkBit metadata id=" + controllerId + ", key=" + key, e); } } - public void deleteFirmwareTargetMetadata(String controllerId, String key) { + /** + * Deletes a single hawkBit target metadata entry. + */ + public void deleteTargetMetadata(String controllerId, String key) { try (Response response = targets.deleteMetadata(controllerId, key)) { if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { - LOG.fine("hawkbit target metadata not found for delete targetId=" + LOG.fine("hawkBit metadata not found for delete id=" + controllerId + ", key=" + key); return; } if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { - LOG.warning("Failed to delete hawkbit target metadata targetId=" + LOG.warning("Failed to delete hawkBit metadata id=" + controllerId + ", key=" + key + ", status=" + response.getStatus()); return; } - LOG.fine("Deleted hawkbit target metadata targetId=" + controllerId + ", key=" + key); + LOG.fine("Deleted hawkBit metadata id=" + controllerId + ", key=" + key); } catch (Exception e) { - LOG.log(Level.WARNING, "Failed to delete hawkbit target metadata targetId=" + LOG.log(Level.WARNING, "Failed to delete hawkBit metadata id=" + controllerId + ", key=" + key, e); } } - /** - * Finds the single asset attribute marked as {@code firmwareTarget}. - * Returns empty if none or more than one is found. - */ - public Optional getFirmwareTargetInfoAttributeName(Asset asset) { - List matchingAttributeNames = asset.getAttributes().values().stream() - .filter(attribute -> hasFirmwareTarget(attribute.getMeta())) - .map(Attribute::getName) - .distinct() - .toList(); - - if (matchingAttributeNames.isEmpty()) { - return Optional.empty(); - } - - if (matchingAttributeNames.size() > 1) { - LOG.warning("Asset type '" + asset.getType() - + "' has multiple attributes with meta item '" - + FirmwareMetaItemType.FIRMWARE_TARGET.getName() + "'"); - return Optional.empty(); - } - - return Optional.of(matchingAttributeNames.getFirst()); + protected TargetCreateRequest buildTargetCreateRequest(Asset asset, String securityToken) { + String controllerId = asset.getId(); + String targetName = asset.getAssetType() + "-" + controllerId; + String targetDescription = "assetId=" + asset.getId() + "; realm=" + asset.getRealm(); + return new TargetCreateRequest(controllerId, targetName, targetDescription, securityToken); } - public boolean hasFirmwareTarget(MetaMap meta) { - return meta != null - && meta.get(FirmwareMetaItemType.FIRMWARE_TARGET) - .flatMap(metaItem -> metaItem.getValue(Boolean.class)) - .orElse(false); + /** + * Creates a hawkBit target for an asset. + * The security token is omitted so hawkBit can generate one. + */ + public Target createTarget(Asset asset) { + return createTarget(asset, null); } - public TargetCreateRequest buildFirmwareTarget(Asset asset) { - String controllerId = asset.getId(); - String targetName = asset.getAssetType() + "-" + controllerId; - String targetDescription = "assetId=" + asset.getId() + "; realm=" + asset.getRealm(); - return new TargetCreateRequest(controllerId, targetName, targetDescription); + /** + * Creates a hawkBit target for an asset using an optional security token. + * If {@code securityToken} is {@code null}, hawkBit can generate one. + */ + public Target createTarget(Asset asset, String securityToken) { + return createTarget(buildTargetCreateRequest(asset, securityToken)); } - public Target createFirmwareTarget(TargetCreateRequest target) { - LOG.info("Creating hawkbit target id=" + target.controllerId()); + /** + * Creates a hawkBit target from a create request. + * Returns {@code null} if creation fails or hawkBit returns no target. + */ + public Target createTarget(TargetCreateRequest target) { + LOG.fine("Creating hawkBit target id=" + target.controllerId()); try (Response response = targets.create(new TargetCreateRequest[]{target})) { if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { - LOG.warning("Failed to create hawkbit target id=" + target.controllerId() + LOG.warning("Failed to create hawkBit target id=" + target.controllerId() + ", status=" + response.getStatus()); return null; } Target[] created = response.readEntity(Target[].class); if (created == null || created.length == 0) { - LOG.warning("hawkbit create returned no targets id=" + target.controllerId()); + LOG.warning("hawkBit create returned no targets id=" + target.controllerId()); return null; } + LOG.info("Created hawkBit target id=" + created[0].controllerId()); return created[0]; } catch (Exception e) { - LOG.log(Level.WARNING, "Failed to create hawkbit target id=" + target.controllerId(), e); + LOG.log(Level.WARNING, "Failed to create hawkBit target id=" + target.controllerId(), e); return null; } } - public void deleteFirmwareTarget(String controllerId) { + /** + * Deletes a hawkBit target by controllerId. + */ + public void deleteTarget(String controllerId) { try (Response response = targets.delete(controllerId)) { if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { - LOG.fine("hawkbit target not found for delete id=" + controllerId); + LOG.fine("hawkBit target not found for delete id=" + controllerId); return; } if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { - LOG.warning("Failed to delete hawkbit target id=" + controllerId + LOG.warning("Failed to delete hawkBit target id=" + controllerId + ", status=" + response.getStatus()); return; } - LOG.info("Deleted hawkbit target id=" + controllerId); + LOG.info("Deleted hawkBit target id=" + controllerId); } catch (Exception e) { - LOG.log(Level.WARNING, "Failed to delete hawkbit target id=" + controllerId, e); + LOG.log(Level.WARNING, "Failed to delete hawkBit target id=" + controllerId, e); } } - /** - * Builds a JSON value containing the hawkBit target's controllerId and securityToken, - * then sends it as an attribute event if the value has changed. - */ - protected void updateFirmwareTargetInfo(AssetEvent assetEvent, String attributeName, Target firmwareTarget) { - Asset asset = assetEvent.getAsset(); - - switch (assetEvent.getCause()) { - case CREATE: - case UPDATE: - try { - Map firmwareTargetInfo = new LinkedHashMap<>(); - firmwareTargetInfo.put("controllerId", firmwareTarget.controllerId()); - firmwareTargetInfo.put("securityToken", firmwareTarget.securityToken()); - String newValueJson = ValueUtil.asJSON(firmwareTargetInfo).orElse(null); - - String existingValueJson = asset.getAttribute(attributeName) - .flatMap(attr -> attr.getValue(String.class)) - .orElse(null); - if (Objects.equals(existingValueJson, newValueJson)) { - LOG.fine("Firmware target info attribute up to date for asset id=" + asset.getId()); - return; - } - - assetProcessingService.sendAttributeEvent( - new AttributeEvent(asset.getId(), attributeName, newValueJson), - getClass().getSimpleName()); - } catch (Exception e) { - LOG.log(Level.WARNING, "Failed to update firmware target info for asset id=" + asset.getId(), e); - } - break; - default: - break; + protected void updateTargetInfoForAttribute(Asset asset, String attributeName, Target target) { + try { + Map targetInfo = new LinkedHashMap<>(); + targetInfo.put("controllerId", target.controllerId()); + targetInfo.put("securityToken", target.securityToken()); + String newValueJson = ValueUtil.asJSON(targetInfo).orElse(null); + + assetProcessingService.sendAttributeEvent( + new AttributeEvent(asset.getId(), attributeName, newValueJson), + getClass().getSimpleName()); + } catch (Exception e) { + LOG.log(Level.WARNING, "Failed to update firmware target info assetId=" + asset.getId(), e); } } @@ -501,7 +441,7 @@ protected void updateFirmwareTargetInfo(AssetEvent assetEvent, String attributeN * Queries hawkBit for a target by controllerId. * Returns {@code null} if the target is not found (404). */ - public Target getFirmwareTarget(String controllerId) { + public Target getTarget(String controllerId) { try (Response response = targets.get(controllerId)) { if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { return null; @@ -514,6 +454,63 @@ public Target getFirmwareTarget(String controllerId) { } } + protected Optional getTargetInfoAttributeName(Asset asset) { + List matchingAttributeNames = asset.getAttributes().values().stream() + .filter(attribute -> hasTargetInfoFlag(attribute.getMeta())) + .map(Attribute::getName) + .distinct() + .toList(); + + if (matchingAttributeNames.isEmpty()) { + return Optional.empty(); + } + + if (matchingAttributeNames.size() > 1) { + LOG.warning("Multiple firmware target attributes assetType=" + asset.getType() + + ", meta=" + FirmwareMetaItemType.FIRMWARE_TARGET.getName()); + return Optional.empty(); + } + + return Optional.of(matchingAttributeNames.getFirst()); + } + + protected boolean hasMetadataFlag(String assetType, String attributeName, MetaMap meta) { + if (hasMetadataMetaFlag(meta)) { + return true; + } + + if (assetType == null) { + return false; + } + + Optional assetTypeInfo = ValueUtil.getAssetInfo(assetType); + return assetTypeInfo + .map(typeInfo -> typeInfo.getAttributeDescriptors().values().stream() + .filter(attributeDescriptor -> Objects.equals(attributeDescriptor.getName(), attributeName)) + .anyMatch(attributeDescriptor -> hasMetadataMetaFlag(attributeDescriptor.getMeta()))) + .orElse(false); + } + + protected boolean hasMetadataMetaFlag(MetaMap meta) { + return meta != null + && meta.get(FirmwareMetaItemType.FIRMWARE_METADATA) + .flatMap(metaItem -> metaItem.getValue(Boolean.class)) + .orElse(false); + } + + protected boolean hasTargetInfoFlag(MetaMap meta) { + return meta != null + && meta.get(FirmwareMetaItemType.FIRMWARE_TARGET) + .flatMap(metaItem -> metaItem.getValue(Boolean.class)) + .orElse(false); + } + + protected boolean isEmptyAttributeValue(Object value) { + return value == null || ValueUtil.getStringCoerced(value) + .map(String::isEmpty) + .orElse(false); + } + /** * Returns the realm this service is bound to. Firmware endpoints are scoped to it. */ diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/FirmwareMetaItemType.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/FirmwareMetaItemType.java index dc9d268..0b1351a 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/FirmwareMetaItemType.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/FirmwareMetaItemType.java @@ -36,7 +36,6 @@ public final class FirmwareMetaItemType { /** * Can be used on any attribute to indicate that this attribute should be synced as metadata to the corresponding * target in hawkBit, enabling hawkBit target filters on specific metadata values. - * Requires the parent asset to be synced to hawkBit via the firmwareTarget metaItem. */ public static final MetaItemDescriptor FIRMWARE_METADATA = new MetaItemDescriptor<>( "firmwareMetadata", ValueType.BOOLEAN); diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetCreateRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetCreateRequest.java index 155dd54..36e83a3 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetCreateRequest.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetCreateRequest.java @@ -19,8 +19,10 @@ */ package org.openremote.extension.hawkbit.model.hawkbit; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +@JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public record TargetCreateRequest(String controllerId, String name, String description) { +public record TargetCreateRequest(String controllerId, String name, String description, String securityToken) { } diff --git a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy index 36ef2dc..f72e2e0 100644 --- a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy +++ b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy @@ -24,6 +24,7 @@ import org.openremote.extension.hawkbit.manager.hawkbit.HawkbitTargetsClient import org.openremote.extension.hawkbit.model.FirmwareMetaItemType import org.openremote.extension.hawkbit.model.hawkbit.MetadataUpdateRequest import org.openremote.extension.hawkbit.model.hawkbit.Target +import org.openremote.extension.hawkbit.model.hawkbit.TargetCreateRequest import org.openremote.model.asset.Asset import org.openremote.model.asset.AssetEvent import org.openremote.model.attribute.* @@ -41,12 +42,12 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain * with any asset type. */ static class TestableHawkbitFirmwareService extends HawkbitFirmwareService { - Optional getFirmwareTargetInfoAttributeName(Asset asset) { + Optional getTargetInfoAttributeName(Asset asset) { return Optional.of("firmwareTarget") } } - def "getFirmwareTargetInfoAttributeName rejects multiple marked attributes"() { + def "getTargetInfoAttributeName rejects multiple marked attributes"() { given: "an asset with multiple attributes marked as firmware target" def service = new HawkbitFirmwareService() def meta = new MetaMap() @@ -60,7 +61,7 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain ]) expect: "ambiguous firmware target info attributes are ignored" - service.getFirmwareTargetInfoAttributeName(asset) == Optional.empty() + service.getTargetInfoAttributeName(asset) == Optional.empty() } def "handleAssetChange with CREATE cause creates target when it does not exist"() { @@ -78,7 +79,9 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain then: "hawkBit checks (404), creates, then uses the created target to update target info" 1 * service.targets.get(CONTROLLER_ID) >> Response.status(Response.Status.NOT_FOUND).build() - 1 * service.targets.create(_) >> Response.ok(new Target[]{createdTarget}).build() + 1 * service.targets.create({ TargetCreateRequest[] targets -> + targets.length == 1 && targets[0].securityToken() == null + }) >> Response.ok(new Target[]{createdTarget}).build() } def "handleAssetChange with CREATE cause skips create when target already exists"() { @@ -135,10 +138,12 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain then: "hawkBit queries (404), creates, then uses the created target for info update" 1 * service.targets.get(CONTROLLER_ID) >> Response.status(Response.Status.NOT_FOUND).build() - 1 * service.targets.create(_) >> Response.ok(new Target[]{createdTarget}).build() + 1 * service.targets.create({ TargetCreateRequest[] targets -> + targets.length == 1 && targets[0].securityToken() == null + }) >> Response.ok(new Target[]{createdTarget}).build() } - def "handleAssetChange with UPDATE cause logs warning when getFirmwareTarget throws exception"() { + def "handleAssetChange with UPDATE cause logs warning when getTarget throws exception"() { given: "a service with mocked targets client that throws" def service = new TestableHawkbitFirmwareService() service.targets = Mock(HawkbitTargetsClient) @@ -156,6 +161,29 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain 0 * service.targets.delete(_) } + def "createTarget with security token forwards token in create request"() { + given: "a service with mocked targets client" + def service = new TestableHawkbitFirmwareService() + service.targets = Mock(HawkbitTargetsClient) + def createdTarget = new Target(CONTROLLER_ID, null, null, "custom-token", null, null, null, null, null, null, null, null, null) + + def asset = Mock(Asset) + asset.getId() >> CONTROLLER_ID + asset.getAssetType() >> "test:asset:type" + asset.getRealm() >> "master" + + when: "creating a target with a custom security token" + def result = service.createTarget(asset, "custom-token") + + then: "the token is forwarded to hawkBit" + 1 * service.targets.create({ TargetCreateRequest[] targets -> + targets.length == 1 && + targets[0].controllerId() == CONTROLLER_ID && + targets[0].securityToken() == "custom-token" + }) >> Response.ok(new Target[]{createdTarget}).build() + result == createdTarget + } + def "handleAssetChange with DELETE cause deletes target"() { given: "a service with mocked targets client" def service = new TestableHawkbitFirmwareService() From 752712e54ff58ca90e1f5a6e40e39cc7e52d05d0 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Wed, 20 May 2026 17:32:07 +0200 Subject: [PATCH 16/18] Add createUpdateTarget method, allows updating target properties if it already exists, e.g. overwrite the securityToken on re-provision. --- .../manager/HawkbitFirmwareService.java | 52 +++++++++++++++++++ .../manager/hawkbit/HawkbitTargetsClient.java | 4 +- .../model/hawkbit/TargetUpdateRequest.java | 28 ++++++++++ .../manager/HawkbitFirmwareServiceTest.groovy | 25 +++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetUpdateRequest.java diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java index efd7297..4ed0f75 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java @@ -36,6 +36,7 @@ import org.openremote.extension.hawkbit.model.hawkbit.MetadataUpdateRequest; import org.openremote.extension.hawkbit.model.hawkbit.Target; import org.openremote.extension.hawkbit.model.hawkbit.TargetCreateRequest; +import org.openremote.extension.hawkbit.model.hawkbit.TargetUpdateRequest; import org.openremote.manager.asset.AssetProcessingService; import org.openremote.manager.event.ClientEventService; import org.openremote.manager.security.ManagerIdentityService; @@ -402,6 +403,57 @@ public Target createTarget(TargetCreateRequest target) { } } + /** + * Creates or updates a hawkBit target for an asset. + */ + public Target createUpdateTarget(Asset asset, String securityToken) { + String controllerId = asset.getId(); + Target existingTarget; + try { + existingTarget = getTarget(controllerId); + } catch (Exception e) { + LOG.log(Level.WARNING, "hawkBit target lookup failed id=" + controllerId + ", skipping create/update", e); + return null; + } + + if (existingTarget != null) { + LOG.fine("hawkBit target exists id=" + controllerId + ", updating"); + return updateTarget(controllerId, new TargetUpdateRequest(null, null, securityToken)); + } + + LOG.fine("hawkBit target missing id=" + controllerId + ", creating"); + return createTarget(asset, securityToken); + } + + /** + * Updates a hawkBit target by controllerId. + * Returns {@code null} if the target is missing or the update fails. + */ + public Target updateTarget(String controllerId, TargetUpdateRequest target) { + LOG.fine("Updating hawkBit target id=" + controllerId); + try (Response response = targets.update(controllerId, target)) { + if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { + LOG.fine("hawkBit target not found for update id=" + controllerId); + return null; + } + if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { + LOG.warning("Failed to update hawkBit target id=" + controllerId + + ", status=" + response.getStatus()); + return null; + } + Target updated = response.hasEntity() ? response.readEntity(Target.class) : getTarget(controllerId); + if (updated == null) { + LOG.info("Updated hawkBit target id=" + controllerId); + return null; + } + LOG.info("Updated hawkBit target id=" + updated.controllerId()); + return updated; + } catch (Exception e) { + LOG.log(Level.WARNING, "Failed to update hawkBit target id=" + controllerId, e); + return null; + } + } + /** * Deletes a hawkBit target by controllerId. */ diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsClient.java index dbe8cc0..25944c2 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsClient.java @@ -22,8 +22,8 @@ import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; import org.openremote.extension.hawkbit.model.hawkbit.MetadataUpdateRequest; -import org.openremote.extension.hawkbit.model.hawkbit.Target; import org.openremote.extension.hawkbit.model.hawkbit.TargetCreateRequest; +import org.openremote.extension.hawkbit.model.hawkbit.TargetUpdateRequest; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.openremote.extension.hawkbit.manager.hawkbit.HawkbitMediaType.APPLICATION_HAL_JSON; @@ -50,7 +50,7 @@ public interface HawkbitTargetsClient { @Path("{id}") @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) - Response update(@PathParam("id") String id, Target target); + Response update(@PathParam("id") String id, TargetUpdateRequest target); @DELETE @Path("{id}") diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetUpdateRequest.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetUpdateRequest.java new file mode 100644 index 0000000..2c86f69 --- /dev/null +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/hawkbit/TargetUpdateRequest.java @@ -0,0 +1,28 @@ +/* + * Copyright 2025, OpenRemote Inc. + * + * See the CONTRIBUTORS.txt file in the distribution for a + * full listing of individual contributors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.openremote.extension.hawkbit.model.hawkbit; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record TargetUpdateRequest(String name, String description, String securityToken) { +} diff --git a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy index f72e2e0..07335a6 100644 --- a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy +++ b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy @@ -25,6 +25,7 @@ import org.openremote.extension.hawkbit.model.FirmwareMetaItemType import org.openremote.extension.hawkbit.model.hawkbit.MetadataUpdateRequest import org.openremote.extension.hawkbit.model.hawkbit.Target import org.openremote.extension.hawkbit.model.hawkbit.TargetCreateRequest +import org.openremote.extension.hawkbit.model.hawkbit.TargetUpdateRequest import org.openremote.model.asset.Asset import org.openremote.model.asset.AssetEvent import org.openremote.model.attribute.* @@ -184,6 +185,30 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain result == createdTarget } + def "createUpdateTarget updates token when target exists"() { + given: "a service with mocked targets client" + def service = new TestableHawkbitFirmwareService() + service.targets = Mock(HawkbitTargetsClient) + def existingTarget = new Target(CONTROLLER_ID, null, null, "old-token", null, null, null, null, null, null, null, null, null) + def updatedTarget = new Target(CONTROLLER_ID, null, null, "new-token", null, null, null, null, null, null, null, null, null) + + def asset = Mock(Asset) + asset.getId() >> CONTROLLER_ID + asset.getAssetType() >> "test:asset:type" + asset.getRealm() >> "master" + + when: "creating or updating a target with a custom security token" + def result = service.createUpdateTarget(asset, "new-token") + + then: "the existing target is updated with the new token" + 1 * service.targets.get(CONTROLLER_ID) >> Response.ok(existingTarget).build() + 1 * service.targets.update(CONTROLLER_ID, { TargetUpdateRequest target -> + target.securityToken() == "new-token" + }) >> Response.ok(updatedTarget).build() + 0 * service.targets.create(_) + result == updatedTarget + } + def "handleAssetChange with DELETE cause deletes target"() { given: "a service with mocked targets client" def service = new TestableHawkbitFirmwareService() From 72478edf103ac50c1028b279615c65fe2c9bf6c4 Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Mon, 25 May 2026 15:37:46 +0200 Subject: [PATCH 17/18] Add missing guard in createTarget --- .../manager/HawkbitFirmwareService.java | 18 +++++++++++++++++ .../manager/HawkbitFirmwareServiceTest.groovy | 20 +++++++++++-------- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java index 4ed0f75..b75680b 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/HawkbitFirmwareService.java @@ -375,6 +375,9 @@ public Target createTarget(Asset asset) { * If {@code securityToken} is {@code null}, hawkBit can generate one. */ public Target createTarget(Asset asset, String securityToken) { + if (!isInHawkbitRealm(asset)) { + return null; + } return createTarget(buildTargetCreateRequest(asset, securityToken)); } @@ -407,6 +410,9 @@ public Target createTarget(TargetCreateRequest target) { * Creates or updates a hawkBit target for an asset. */ public Target createUpdateTarget(Asset asset, String securityToken) { + if (!isInHawkbitRealm(asset)) { + return null; + } String controllerId = asset.getId(); Target existingTarget; try { @@ -563,6 +569,18 @@ protected boolean isEmptyAttributeValue(Object value) { .orElse(false); } + /** + * Targets are only managed for assets in the configured hawkBit realm. + */ + protected boolean isInHawkbitRealm(Asset asset) { + if (!Objects.equals(asset.getRealm(), hawkbitRealm)) { + LOG.warning("Asset realm=" + asset.getRealm() + " is not the hawkBit realm=" + hawkbitRealm + + ", skipping hawkBit target id=" + asset.getId()); + return false; + } + return true; + } + /** * Returns the realm this service is bound to. Firmware endpoints are scoped to it. */ diff --git a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy index 07335a6..d40868a 100644 --- a/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy +++ b/hawkbit/src/test/groovy/org/openremote/extension/hawkbit/manager/HawkbitFirmwareServiceTest.groovy @@ -43,6 +43,10 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain * with any asset type. */ static class TestableHawkbitFirmwareService extends HawkbitFirmwareService { + TestableHawkbitFirmwareService() { + hawkbitRealm = "test-realm" + } + Optional getTargetInfoAttributeName(Asset asset) { return Optional.of("firmwareTarget") } @@ -72,7 +76,7 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain def createdTarget = new Target(CONTROLLER_ID, null, null, "token", null, null, null, null, null, null, null, null, null) def asset = Mock(Asset) asset.getId() >> CONTROLLER_ID - asset.getRealm() >> "master" + asset.getRealm() >> "test-realm" asset.getAttributes() >> new AttributeMap() when: "handling an asset CREATE event" @@ -93,7 +97,7 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain def asset = Mock(Asset) asset.getId() >> CONTROLLER_ID - asset.getRealm() >> "master" + asset.getRealm() >> "test-realm" asset.getAttributes() >> new AttributeMap() when: "handling an asset CREATE event for an already-existing target" @@ -112,7 +116,7 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain def asset = Mock(Asset) asset.getId() >> CONTROLLER_ID - asset.getRealm() >> "master" + asset.getRealm() >> "test-realm" asset.getAttributes() >> new AttributeMap() when: "handling an asset UPDATE event" @@ -131,7 +135,7 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain def asset = Mock(Asset) asset.getId() >> CONTROLLER_ID - asset.getRealm() >> "master" + asset.getRealm() >> "test-realm" asset.getAttributes() >> new AttributeMap() when: "handling an asset UPDATE event for a missing target" @@ -151,7 +155,7 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain def asset = Mock(Asset) asset.getId() >> CONTROLLER_ID - asset.getRealm() >> "master" + asset.getRealm() >> "test-realm" when: "handling an asset UPDATE event when hawkBit query fails" service.handleAssetChange(new AssetEvent(AssetEvent.Cause.UPDATE, asset)) @@ -171,7 +175,7 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain def asset = Mock(Asset) asset.getId() >> CONTROLLER_ID asset.getAssetType() >> "test:asset:type" - asset.getRealm() >> "master" + asset.getRealm() >> "test-realm" when: "creating a target with a custom security token" def result = service.createTarget(asset, "custom-token") @@ -195,7 +199,7 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain def asset = Mock(Asset) asset.getId() >> CONTROLLER_ID asset.getAssetType() >> "test:asset:type" - asset.getRealm() >> "master" + asset.getRealm() >> "test-realm" when: "creating or updating a target with a custom security token" def result = service.createUpdateTarget(asset, "new-token") @@ -216,7 +220,7 @@ class HawkbitFirmwareServiceTest extends Specification implements ManagerContain def asset = Mock(Asset) asset.getId() >> CONTROLLER_ID - asset.getRealm() >> "master" + asset.getRealm() >> "test-realm" when: "handling an asset DELETE event" service.handleAssetChange(new AssetEvent(AssetEvent.Cause.DELETE, asset)) From d6f2f1ed381400ec36394ec27e0878fec31dc68e Mon Sep 17 00:00:00 2001 From: dominiquekleeven <10584854+dominiquekleeven@users.noreply.github.com> Date: Wed, 27 May 2026 15:00:27 +0200 Subject: [PATCH 18/18] Add action status endpoint --- hawkbit/README.md | 2 +- .../manager/hawkbit/HawkbitTargetsClient.java | 8 ++++++++ .../manager/resource/TargetResourceImpl.java | 9 +++++++++ .../hawkbit/model/resource/TargetResource.java | 18 ++++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/hawkbit/README.md b/hawkbit/README.md index 853da4e..f35e4a8 100644 --- a/hawkbit/README.md +++ b/hawkbit/README.md @@ -152,7 +152,7 @@ OpenRemote Manager exposes endpoints that forward to the configured hawkBit inst | Resource | Path | Functionality | |---|---|---| -| Firmware targets | `firmware/target` | List targets, get target details, metadata, assigned and installed distribution sets, actions | +| Firmware targets | `firmware/target` | List targets, get target details, metadata, assigned and installed distribution sets, actions and action status messages | | Software module types | `firmware/softwaremoduletype` | Create, list, get and delete software module types | | Software modules | `firmware/softwaremodule` | Create, list, get and delete software modules, list and upload artifacts | | Distribution set types | `firmware/distributionsettype` | Create, list, get and delete distribution set types, list module type assignments | diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsClient.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsClient.java index 25944c2..bd22022 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsClient.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/hawkbit/HawkbitTargetsClient.java @@ -94,6 +94,14 @@ Response getActions(@PathParam("id") String id, @Produces(APPLICATION_HAL_JSON) Response getAction(@PathParam("id") String id, @PathParam("actionId") Long actionId); + @GET + @Path("{id}/actions/{actionId}/status") + @Produces(APPLICATION_HAL_JSON) + Response getActionStatus(@PathParam("id") String id, + @PathParam("actionId") Long actionId, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + @DELETE @Path("{id}/actions/{actionId}") Response cancelAction(@PathParam("id") String id, diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java index b8cce71..8d3983e 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/manager/resource/TargetResourceImpl.java @@ -91,6 +91,15 @@ public Response getAction(RequestParams requestParams, String realm, String id, () -> hawkbitFirmwareService.targets().getAction(id, actionId)); } + @Override + public Response getActionStatus(RequestParams requestParams, String realm, String id, Long actionId, + Integer offset, Integer limit) { + requireHawkbitRealmAccess(realm); + return HawkbitResponseProxy.proxy( + "Failed to retrieve status for action '" + actionId + "' on firmware target '" + id + "'", + () -> hawkbitFirmwareService.targets().getActionStatus(id, actionId, offset, limit)); + } + @Override public Response cancelAction(RequestParams requestParams, String realm, String id, Long actionId, Boolean force) { requireHawkbitRealmAccess(realm); diff --git a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java index 5346d49..45aff07 100644 --- a/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java +++ b/hawkbit/src/main/java/org/openremote/extension/hawkbit/model/resource/TargetResource.java @@ -127,6 +127,24 @@ Response getAction(@BeanParam RequestParams requestParams, @PathParam("id") String id, @PathParam("actionId") Long actionId); + /** + * Retrieve the status history for a single action, paged. + *

+ * Each entry carries the {@code messages} the controller reported over the + * DDI feedback channel (e.g. OTA progress or failure detail), plus the + * reported status code. + */ + @GET + @Path("{id}/actions/{actionId}/status") + @Produces(APPLICATION_JSON) + @RolesAllowed({Constants.READ_ADMIN_ROLE}) + Response getActionStatus(@BeanParam RequestParams requestParams, + @QueryParam("realm") String realm, + @PathParam("id") String id, + @PathParam("actionId") Long actionId, + @QueryParam("offset") Integer offset, + @QueryParam("limit") Integer limit); + /** * Cancel an in-flight action on a firmware target. *