Soft Module metadata as complex map value (#2568)
--------- Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -33,7 +33,6 @@ import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TenantMetaData;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
@@ -133,7 +132,7 @@ public final class DataConversionHelper {
|
||||
final Target target, final Action uAction,
|
||||
final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement,
|
||||
final HttpRequest request, final ControllerManagement controllerManagement) {
|
||||
final Map<Long, List<SoftwareModuleMetadata>> metadata = controllerManagement
|
||||
final Map<Long, Map<String, String>> metadata = controllerManagement
|
||||
.findTargetVisibleMetaDataBySoftwareModuleId(uAction.getDistributionSet().getModules().stream()
|
||||
.map(SoftwareModule::getId).toList());
|
||||
|
||||
@@ -155,10 +154,10 @@ public final class DataConversionHelper {
|
||||
.toList());
|
||||
}
|
||||
|
||||
private static List<DdiMetadata> mapMetadata(final List<SoftwareModuleMetadata> metadata) {
|
||||
private static List<DdiMetadata> mapMetadata(final Map<String, String> metadata) {
|
||||
return CollectionUtils.isEmpty(metadata)
|
||||
? null
|
||||
: metadata.stream().map(md -> new DdiMetadata(md.getKey(), md.getValue())).toList();
|
||||
: metadata.entrySet().stream().map(md -> new DdiMetadata(md.getKey(), md.getValue())).toList();
|
||||
}
|
||||
|
||||
private static String mapChunkLegacyKeys(final String key) {
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValueCreate;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
@@ -253,10 +254,8 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
final Artifact artifactSignature = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
|
||||
getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
|
||||
|
||||
softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(getOsModule(ds))
|
||||
.key(visibleMetadataOsKey).value(visibleMetadataOsValue).targetVisible(true));
|
||||
softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(getOsModule(ds))
|
||||
.key("metaDataNotVisible").value("withValue").targetVisible(false));
|
||||
softwareModuleManagement.createMetadata(getOsModule(ds), visibleMetadataOsKey, new MetadataValueCreate(visibleMetadataOsValue, true));
|
||||
softwareModuleManagement.createMetadata(getOsModule(ds), "metaDataNotVisible", new MetadataValueCreate("withValue", false));
|
||||
|
||||
final Target savedTarget = createTargetAndAssertNoActiveActions();
|
||||
|
||||
@@ -374,10 +373,8 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
final Artifact artifactSignature = testdataFactory.createArtifact(
|
||||
nextBytes(ARTIFACT_SIZE), getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
|
||||
|
||||
softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(getOsModule(ds))
|
||||
.key("metaDataVisible").value("withValue").targetVisible(true));
|
||||
softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(getOsModule(ds))
|
||||
.key("metaDataNotVisible").value("withValue").targetVisible(false));
|
||||
softwareModuleManagement.createMetadata(getOsModule(ds), "metaDataVisible", new MetadataValueCreate("withValue", true));
|
||||
softwareModuleManagement.createMetadata(getOsModule(ds), "metaDataNotVisible", new MetadataValueCreate("withValue", false));
|
||||
|
||||
final Target savedTarget = createTargetAndAssertNoActiveActions();
|
||||
|
||||
|
||||
@@ -29,11 +29,6 @@ import java.util.stream.StreamSupport;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.ApiType;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrl;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrlHandler;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.URLPlaceholder;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.URLPlaceholder.SoftwareData;
|
||||
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
|
||||
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
|
||||
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
|
||||
@@ -49,11 +44,15 @@ import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfTarget;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.ApiType;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrl;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrlHandler;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.URLPlaceholder;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.URLPlaceholder.SoftwareData;
|
||||
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
|
||||
@@ -71,7 +70,6 @@ import org.eclipse.hawkbit.repository.model.ActionProperties;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TenantMetaData;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
@@ -81,7 +79,6 @@ import org.springframework.amqp.core.MessageBuilder;
|
||||
import org.springframework.amqp.core.MessageProperties;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -124,7 +121,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
|
||||
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
|
||||
final TargetManagement targetManagement,
|
||||
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement, final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
|
||||
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement,
|
||||
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
|
||||
final DeploymentManagement deploymentManagement,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
super(rabbitTemplate);
|
||||
@@ -187,15 +185,14 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
|
||||
protected void sendUpdateMessageToTarget(
|
||||
final ActionProperties actionsProps, final Target target,
|
||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
||||
final Map<SoftwareModule, Map<String, String>> softwareModules) {
|
||||
final Map<String, ActionProperties> actionProp = new HashMap<>();
|
||||
actionProp.put(target.getControllerId(), actionsProps);
|
||||
sendUpdateMessageToTargets(actionProp, Collections.singletonList(target), softwareModules);
|
||||
}
|
||||
|
||||
protected DmfDownloadAndUpdateRequest createDownloadAndUpdateRequest(
|
||||
final Target target, final Long actionId,
|
||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
||||
final Target target, final Long actionId, final Map<SoftwareModule, Map<String, String>> softwareModules) {
|
||||
return new DmfDownloadAndUpdateRequest(
|
||||
actionId,
|
||||
systemSecurityContext.runAsSystem(target::getSecurityToken),
|
||||
@@ -273,7 +270,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
}
|
||||
|
||||
protected DmfConfirmRequest createConfirmRequest(
|
||||
final Target target, final Long actionId, final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
||||
final Target target, final Long actionId, final Map<SoftwareModule, Map<String, String>> softwareModules) {
|
||||
return new DmfConfirmRequest(
|
||||
actionId,
|
||||
systemSecurityContext.runAsSystem(target::getSecurityToken),
|
||||
@@ -282,7 +279,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
|
||||
void sendMultiActionRequestToTarget(
|
||||
final Target target, final List<Action> actions,
|
||||
final Function<SoftwareModule, List<SoftwareModuleMetadata>> getSoftwareModuleMetaData) {
|
||||
final Function<SoftwareModule, Map<String, String>> getSoftwareModuleMetaData) {
|
||||
final URI targetAddress = target.getAddress();
|
||||
if (!IpUtil.isAmqpUri(targetAddress) || CollectionUtils.isEmpty(actions)) {
|
||||
return;
|
||||
@@ -295,9 +292,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
target, action,
|
||||
action.getDistributionSet().getModules().stream()
|
||||
.collect(Collectors.toMap(Function.identity(), module -> {
|
||||
final List<SoftwareModuleMetadata> softwareModuleMetadata = getSoftwareModuleMetaData.apply(
|
||||
module);
|
||||
return softwareModuleMetadata == null ? Collections.emptyList() : softwareModuleMetadata;
|
||||
final Map<String, String> softwareModuleMetadata = getSoftwareModuleMetaData.apply(module);
|
||||
return softwareModuleMetadata == null ? Collections.emptyMap() : softwareModuleMetadata;
|
||||
})));
|
||||
final int weight = deploymentManagement.getWeightConsideringDefault(action);
|
||||
return new DmfMultiActionRequest.DmfMultiActionElement(getEventTypeForAction(action), actionRequest, weight);
|
||||
@@ -424,14 +420,14 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
private void sendUpdateMessageToTargets(
|
||||
final Long dsId, final Map<String, ActionProperties> actionsPropsByTargetId, final List<Target> targets) {
|
||||
distributionSetManagement.get(dsId).ifPresent(ds -> {
|
||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules = getSoftwareModulesWithMetadata(ds);
|
||||
final Map<SoftwareModule, Map<String, String>> softwareModules = getSoftwareModulesWithMetadata(ds);
|
||||
sendUpdateMessageToTargets(actionsPropsByTargetId, targets, softwareModules);
|
||||
});
|
||||
}
|
||||
|
||||
private void sendUpdateMessageToTargets(
|
||||
final Map<String, ActionProperties> actionsPropsByTargetId,
|
||||
final List<Target> targets, final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
||||
final List<Target> targets, final Map<SoftwareModule, Map<String, String>> softwareModules) {
|
||||
if (!targets.isEmpty() && isBatchAssignmentsEnabled()) {
|
||||
sendBatchUpdateMessage(actionsPropsByTargetId, targets, softwareModules);
|
||||
} else {
|
||||
@@ -455,7 +451,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
.flatMap(ds -> ds.getModules().stream())
|
||||
.map(SoftwareModule::getId))
|
||||
.collect(Collectors.toSet());
|
||||
final Map<Long, List<SoftwareModuleMetadata>> getSoftwareModuleMetadata =
|
||||
final Map<Long, ? extends Map<String, String>> getSoftwareModuleMetadata =
|
||||
allSmIds.isEmpty()
|
||||
? Collections.emptyMap()
|
||||
: softwareModuleManagement.findMetaDataBySoftwareModuleIdsAndTargetVisible(allSmIds);
|
||||
@@ -467,7 +463,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
|
||||
private DmfActionRequest createDmfActionRequest(
|
||||
final Target target, final Action action,
|
||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
||||
final Map<SoftwareModule, Map<String, String>> softwareModules) {
|
||||
if (action.isCancelingOrCanceled()) {
|
||||
return new DmfActionRequest(action.getId());
|
||||
} else if (action.isWaitingConfirmation()) {
|
||||
@@ -477,8 +473,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
}
|
||||
|
||||
private void sendSingleUpdateMessage(
|
||||
final ActionProperties action, final Target target,
|
||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules) {
|
||||
final ActionProperties action, final Target target, final Map<SoftwareModule, Map<String, String>> modules) {
|
||||
final String tenant = action.getTenant();
|
||||
|
||||
final URI targetAddress = target.getAddress();
|
||||
@@ -531,7 +526,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
}
|
||||
|
||||
private List<DmfSoftwareModule> convertToAmqpSoftwareModules(
|
||||
final Target target, final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
||||
final Target target, final Map<SoftwareModule, Map<String, String>> softwareModules) {
|
||||
return Optional.ofNullable(softwareModules)
|
||||
.map(Map::entrySet)
|
||||
.map(Set::stream)
|
||||
@@ -539,19 +534,18 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private DmfSoftwareModule convertToAmqpSoftwareModule(
|
||||
final Target target, final Entry<SoftwareModule, List<SoftwareModuleMetadata>> entry) {
|
||||
private DmfSoftwareModule convertToAmqpSoftwareModule(final Target target, final Entry<SoftwareModule, Map<String, String>> entry) {
|
||||
return new DmfSoftwareModule(
|
||||
entry.getKey().getId(),
|
||||
entry.getKey().getType().getKey(),
|
||||
entry.getKey().getVersion(),
|
||||
entry.getKey().isEncrypted() ? Boolean.TRUE : null,
|
||||
convertArtifacts(target, entry.getKey().getArtifacts()),
|
||||
CollectionUtils.isEmpty(entry.getValue()) ? null :convertMetadata(entry.getValue()));
|
||||
CollectionUtils.isEmpty(entry.getValue()) ? null : convertMetadata(entry.getValue()));
|
||||
}
|
||||
|
||||
private List<DmfMetadata> convertMetadata(final List<SoftwareModuleMetadata> metadata) {
|
||||
return metadata.stream().map(md -> new DmfMetadata(md.getKey(), md.getValue())).toList();
|
||||
private List<DmfMetadata> convertMetadata(final Map<String, String> metadata) {
|
||||
return metadata.entrySet().stream().map(md -> new DmfMetadata(md.getKey(), md.getValue())).toList();
|
||||
}
|
||||
|
||||
private List<DmfArtifact> convertArtifacts(final Target target, final List<Artifact> localArtifacts) {
|
||||
@@ -559,8 +553,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return localArtifacts.stream().map(localArtifact -> convertArtifact(target, localArtifact))
|
||||
.toList();
|
||||
return localArtifacts.stream().map(localArtifact -> convertArtifact(target, localArtifact)).toList();
|
||||
}
|
||||
|
||||
private DmfArtifact convertArtifact(final Target target, final Artifact localArtifact) {
|
||||
@@ -582,19 +575,22 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
);
|
||||
}
|
||||
|
||||
private Map<SoftwareModule, List<SoftwareModuleMetadata>> getSoftwareModulesWithMetadata(final DistributionSet distributionSet) {
|
||||
return distributionSet.getModules().stream().collect(Collectors.toMap(Function.identity(), this::getSoftwareModuleMetadata));
|
||||
}
|
||||
|
||||
private List<SoftwareModuleMetadata> getSoftwareModuleMetadata(final SoftwareModule module) {
|
||||
return softwareModuleManagement.findMetaDataBySoftwareModuleIdAndTargetVisible(
|
||||
module.getId(), PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT)).getContent();
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<SoftwareModule, Map<String, String>> getSoftwareModulesWithMetadata(final DistributionSet distributionSet) {
|
||||
final Map<Long, Map<String, String>> softwareModuleMetadata =
|
||||
softwareModuleManagement.findMetaDataBySoftwareModuleIdsAndTargetVisible(
|
||||
distributionSet.getModules().stream()
|
||||
.map(SoftwareModule::getId)
|
||||
.toList());
|
||||
return distributionSet.getModules().stream()
|
||||
.collect(Collectors.toMap(
|
||||
Function.identity(),
|
||||
module -> softwareModuleMetadata.getOrDefault(module.getId(), Collections.emptyMap())));
|
||||
}
|
||||
|
||||
private void sendBatchUpdateMessage(
|
||||
final Map<String, ActionProperties> actions, final List<Target> targets,
|
||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules) {
|
||||
|
||||
final Map<SoftwareModule, Map<String, String>> modules) {
|
||||
final List<DmfTarget> dmfTargets = targets.stream()
|
||||
.filter(target -> IpUtil.isAmqpUri(target.getAddress()))
|
||||
.map(t -> convertToDmfTarget(t, actions.get(t.getControllerId()).getId()))
|
||||
|
||||
@@ -51,7 +51,6 @@ import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionProperties;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
||||
@@ -351,7 +350,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
||||
.flatMap(ds -> ds.getModules().stream())
|
||||
.map(SoftwareModule::getId)
|
||||
.collect(Collectors.toSet());
|
||||
final Map<Long, List<SoftwareModuleMetadata>> getSoftwareModuleMetadata =
|
||||
final Map<Long, Map<String, String>> getSoftwareModuleMetadata =
|
||||
allSmIds.isEmpty() ? Collections.emptyMap() : controllerManagement.findTargetVisibleMetaDataBySoftwareModuleId(allSmIds);
|
||||
|
||||
amqpMessageDispatcherService.sendMultiActionRequestToTarget(target, actions, module -> getSoftwareModuleMetadata.get(module.getId()));
|
||||
@@ -373,11 +372,11 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<SoftwareModule, List<SoftwareModuleMetadata>> getSoftwareModulesWithMetadata(final DistributionSet distributionSet) {
|
||||
private Map<SoftwareModule, Map<String, String>> getSoftwareModulesWithMetadata(final DistributionSet distributionSet) {
|
||||
final List<Long> smIds = distributionSet.getModules().stream().map(SoftwareModule::getId).toList();
|
||||
final Map<Long, List<SoftwareModuleMetadata>> metadata = controllerManagement.findTargetVisibleMetaDataBySoftwareModuleId(smIds);
|
||||
final Map<Long, Map<String, String>> metadata = controllerManagement.findTargetVisibleMetaDataBySoftwareModuleId(smIds);
|
||||
return distributionSet.getModules().stream().collect(Collectors.toMap(
|
||||
Function.identity(), sm -> metadata.getOrDefault(sm.getId(), Collections.emptyList())));
|
||||
Function.identity(), sm -> metadata.getOrDefault(sm.getId(), Collections.emptyMap())));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.io.InputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
@@ -35,7 +36,6 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtSoftwareModuleMapper;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
@@ -43,7 +43,8 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValue;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValueCreate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -67,7 +68,6 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
|
||||
private final ArtifactUrlHandler artifactUrlHandler;
|
||||
private final MgmtSoftwareModuleMapper mgmtSoftwareModuleMapper;
|
||||
private final SystemManagement systemManagement;
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
MgmtSoftwareModuleResource(
|
||||
final ArtifactManagement artifactManagement,
|
||||
@@ -75,14 +75,13 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
|
||||
final SoftwareModuleTypeManagement<? extends SoftwareModuleType> softwareModuleTypeManagement,
|
||||
final ArtifactUrlHandler artifactUrlHandler,
|
||||
final MgmtSoftwareModuleMapper mgmtSoftwareModuleMapper,
|
||||
final SystemManagement systemManagement, final EntityFactory entityFactory) {
|
||||
final SystemManagement systemManagement) {
|
||||
this.artifactManagement = artifactManagement;
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.artifactUrlHandler = artifactUrlHandler;
|
||||
this.mgmtSoftwareModuleMapper = mgmtSoftwareModuleMapper;
|
||||
this.systemManagement = systemManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,12 +137,12 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
|
||||
public ResponseEntity<MgmtArtifact> getArtifact(final Long softwareModuleId, final Long artifactId, final Boolean useArtifactUrlHandler) {
|
||||
final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId);
|
||||
|
||||
final MgmtArtifact response = MgmtSoftwareModuleMapper.toResponse(module.getArtifact(artifactId).get());
|
||||
final MgmtArtifact response = MgmtSoftwareModuleMapper.toResponse(module.getArtifact(artifactId).orElseThrow());
|
||||
if (!module.isDeleted()) {
|
||||
if (Boolean.TRUE.equals(useArtifactUrlHandler)) {
|
||||
MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).get(), response, artifactUrlHandler, systemManagement);
|
||||
MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).orElseThrow(), response, artifactUrlHandler, systemManagement);
|
||||
} else {
|
||||
MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).get(), response);
|
||||
MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).orElseThrow(), response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +235,7 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
|
||||
|
||||
@Override
|
||||
public void createMetadata(final Long softwareModuleId, final List<MgmtSoftwareModuleMetadata> metadataRest) {
|
||||
softwareModuleManagement.createMetadata(MgmtSoftwareModuleMapper.fromRequestSwMetadata(entityFactory, softwareModuleId, metadataRest));
|
||||
softwareModuleManagement.createMetadata(softwareModuleId, MgmtSoftwareModuleMapper.fromRequestSwMetadata(metadataRest));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -244,27 +243,24 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
|
||||
// check if software module exists otherwise throw exception immediately
|
||||
findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
|
||||
|
||||
final List<SoftwareModuleMetadata> metadata = softwareModuleManagement.getMetadata(softwareModuleId);
|
||||
final Map<String, MetadataValue> metadata = softwareModuleManagement.getMetadata(softwareModuleId);
|
||||
return ResponseEntity.ok(new PagedList<>(MgmtSoftwareModuleMapper.toResponseSwMetadata(metadata), metadata.size()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleMetadata> getMetadataValue(final Long softwareModuleId, final String metadataKey) {
|
||||
final SoftwareModuleMetadata findOne = softwareModuleManagement.getMetadata(softwareModuleId).stream()
|
||||
.filter(entry -> entry.getKey().equals(metadataKey))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new EntityNotFoundException("SoftwareModule metadata", softwareModuleId + ":" + metadataKey));
|
||||
final MetadataValue metadataValue = softwareModuleManagement.getMetadata(softwareModuleId).get(metadataKey);
|
||||
if (metadataValue == null) {
|
||||
throw new EntityNotFoundException("SoftwareModule metadata", softwareModuleId + ":" + metadataKey);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleMapper.toResponseSwMetadata(findOne));
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleMapper.toResponseSwMetadata(metadataKey, metadataValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMetadata(final Long softwareModuleId, final String metadataKey, final MgmtSoftwareModuleMetadataBodyPut metadata) {
|
||||
softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata()
|
||||
.update(softwareModuleId, metadataKey)
|
||||
.value(metadata.getValue())
|
||||
.targetVisible(metadata.getTargetVisible()));
|
||||
softwareModuleManagement.createMetadata(
|
||||
softwareModuleId, metadataKey, new MetadataValueCreate(metadata.getValue(), metadata.getTargetVisible()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,8 @@ import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
|
||||
@@ -28,7 +30,6 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.MgmtDownloadArtifactResource;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.MgmtSoftwareModuleResource;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
@@ -36,11 +37,11 @@ import org.eclipse.hawkbit.repository.artifact.urlhandler.ApiType;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrl;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrlHandler;
|
||||
import org.eclipse.hawkbit.repository.artifact.urlhandler.URLPlaceholder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValue;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValueCreate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
import org.springframework.hateoas.Link;
|
||||
@@ -59,17 +60,14 @@ public final class MgmtSoftwareModuleMapper {
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
}
|
||||
|
||||
public static List<SoftwareModuleMetadataCreate> fromRequestSwMetadata(
|
||||
final EntityFactory entityFactory, final Long softwareModuleId, final Collection<MgmtSoftwareModuleMetadata> metadata) {
|
||||
public static Map<String, MetadataValueCreate> fromRequestSwMetadata(final Collection<MgmtSoftwareModuleMetadata> metadata) {
|
||||
if (metadata == null) {
|
||||
return Collections.emptyList();
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return metadata.stream()
|
||||
.map(metadataRest -> entityFactory.softwareModuleMetadata().create(softwareModuleId)
|
||||
.key(metadataRest.getKey()).value(metadataRest.getValue())
|
||||
.targetVisible(metadataRest.isTargetVisible()))
|
||||
.toList();
|
||||
return metadata.stream().collect(Collectors.toMap(
|
||||
MgmtSoftwareModuleMetadata::getKey,
|
||||
metadataRest -> new MetadataValueCreate(metadataRest.getValue(), metadataRest.isTargetVisible())));
|
||||
}
|
||||
|
||||
public List<SoftwareModuleManagement.Create> smFromRequest(final Collection<MgmtSoftwareModuleRequestBodyPost> smsRest) {
|
||||
@@ -88,17 +86,17 @@ public final class MgmtSoftwareModuleMapper {
|
||||
return new ResponseList<>(softwareModules.stream().map(MgmtSoftwareModuleMapper::toResponse).toList());
|
||||
}
|
||||
|
||||
public static List<MgmtSoftwareModuleMetadata> toResponseSwMetadata(final Collection<SoftwareModuleMetadata> metadata) {
|
||||
public static List<MgmtSoftwareModuleMetadata> toResponseSwMetadata(final Map<String, ? extends MetadataValue> metadata) {
|
||||
if (metadata == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return metadata.stream().map(MgmtSoftwareModuleMapper::toResponseSwMetadata).toList();
|
||||
return metadata.entrySet().stream().map(e -> toResponseSwMetadata(e.getKey(), e.getValue())).toList();
|
||||
}
|
||||
|
||||
public static MgmtSoftwareModuleMetadata toResponseSwMetadata(final SoftwareModuleMetadata metadata) {
|
||||
public static MgmtSoftwareModuleMetadata toResponseSwMetadata(final String key, final MetadataValue metadata) {
|
||||
final MgmtSoftwareModuleMetadata metadataRest = new MgmtSoftwareModuleMetadata();
|
||||
metadataRest.setKey(metadata.getKey());
|
||||
metadataRest.setKey(key);
|
||||
metadataRest.setValue(metadata.getValue());
|
||||
metadataRest.setTargetVisible(metadata.isTargetVisible());
|
||||
return metadataRest;
|
||||
|
||||
@@ -55,7 +55,8 @@ import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValue;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValueCreate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.test.util.HashGeneratorUtils;
|
||||
@@ -162,8 +163,7 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes
|
||||
final SoftwareModule module = findFirstModuleByType(testdataFactory.createDistributionSet("one"), osType).get();
|
||||
|
||||
for (int index = 0; index < totalMetadata; index++) {
|
||||
softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(module.getId())
|
||||
.key(knownKeyPrefix + index).value(knownValuePrefix + index));
|
||||
softwareModuleManagement.createMetadata(module.getId(), knownKeyPrefix + index, new MetadataValueCreate(knownValuePrefix + index));
|
||||
}
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/metadata",
|
||||
@@ -184,8 +184,7 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes
|
||||
final SoftwareModule module = findFirstModuleByType(testdataFactory.createDistributionSet("one"), osType).orElseThrow();
|
||||
|
||||
for (int index = 0; index < totalMetadata; index++) {
|
||||
softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(module.getId())
|
||||
.key(knownKeyPrefix + index).value(knownValuePrefix + index));
|
||||
softwareModuleManagement.createMetadata(module.getId(), knownKeyPrefix + index, new MetadataValueCreate(knownValuePrefix + index));
|
||||
}
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/metadata",
|
||||
@@ -206,8 +205,7 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes
|
||||
final String knownKey = "knownKey";
|
||||
final String knownValue = "knownValue";
|
||||
final SoftwareModule module = findFirstModuleByType(testdataFactory.createDistributionSet("one"), osType).orElseThrow();
|
||||
softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().create(module.getId()).key(knownKey).value(knownValue));
|
||||
softwareModuleManagement.createMetadata(module.getId(), knownKey, new MetadataValueCreate(knownValue));
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/metadata/{metadataKey}",
|
||||
module.getId(), knownKey))
|
||||
@@ -1424,9 +1422,9 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
assertThat(softwareModuleManagement.getMetadata(sm.getId(), knownKey1))
|
||||
.as("Metadata key is wrong").extracting(SoftwareModuleMetadata::getValue).isEqualTo(knownValue1);
|
||||
.as("Metadata key is wrong").extracting(MetadataValue::getValue).isEqualTo(knownValue1);
|
||||
assertThat(softwareModuleManagement.getMetadata(sm.getId(), knownKey2))
|
||||
.as("Metadata key is wrong").extracting(SoftwareModuleMetadata::getValue).isEqualTo(knownValue2);
|
||||
.as("Metadata key is wrong").extracting(MetadataValue::getValue).isEqualTo(knownValue2);
|
||||
|
||||
// verify quota enforcement
|
||||
final int maxMetaData = quotaManagement.getMaxMetaDataEntriesPerSoftwareModule();
|
||||
@@ -1443,7 +1441,6 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes
|
||||
|
||||
// verify that the number of meta data entries has not changed (we cannot use the PAGE constant here as it tries to sort by ID)
|
||||
assertThat(softwareModuleManagement.getMetadata(sm.getId()).size()).isEqualTo(metaData1.length());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1457,19 +1454,18 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes
|
||||
final String updateValue = "valueForUpdate";
|
||||
|
||||
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
||||
softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().create(sm.getId()).key(knownKey).value(knownValue));
|
||||
softwareModuleManagement.createMetadata(sm.getId(), knownKey, new MetadataValueCreate(knownValue));
|
||||
|
||||
final JSONObject jsonObject = new JSONObject().put("key", knownKey)
|
||||
.put("value", updateValue)
|
||||
.put("targetVisible", true);
|
||||
|
||||
mvc.perform(put("/rest/v1/softwaremodules/{swId}/metadata/{key}", sm.getId(), knownKey).accept(
|
||||
MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON).content(jsonObject.toString()))
|
||||
mvc.perform(put("/rest/v1/softwaremodules/{swId}/metadata/{key}", sm.getId(), knownKey)
|
||||
.accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON).content(jsonObject.toString()))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
final SoftwareModuleMetadata assertDS = softwareModuleManagement.getMetadata(sm.getId(), knownKey);
|
||||
final MetadataValue assertDS = softwareModuleManagement.getMetadata(sm.getId(), knownKey);
|
||||
assertThat(assertDS.getValue()).as("Metadata is wrong").isEqualTo(updateValue);
|
||||
assertThat(assertDS.isTargetVisible()).as("target visible is wrong").isTrue();
|
||||
}
|
||||
@@ -1484,8 +1480,7 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes
|
||||
final String knownValue = "knownValue";
|
||||
|
||||
final long smId = testdataFactory.createSoftwareModuleOs().getId();
|
||||
softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().create(smId).key(knownKey).value(knownValue));
|
||||
softwareModuleManagement.createMetadata(smId, knownKey, new MetadataValueCreate(knownValue));
|
||||
|
||||
mvc.perform(delete("/rest/v1/softwaremodules/{swId}/metadata/{key}", smId, knownKey))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
@@ -1505,8 +1500,7 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes
|
||||
final String knownValue = "knownValue";
|
||||
|
||||
final long smId = testdataFactory.createSoftwareModuleOs().getId();
|
||||
softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().create(smId).key(knownKey).value(knownValue));
|
||||
softwareModuleManagement.createMetadata(smId, knownKey, new MetadataValueCreate(knownValue));
|
||||
|
||||
mvc.perform(delete("/rest/v1/softwaremodules/{swId}/metadata/XXX", smId, knownKey))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
|
||||
@@ -32,7 +32,6 @@ import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.ControllerPollProperties;
|
||||
@@ -69,14 +68,13 @@ public interface ControllerManagement {
|
||||
Optional<SoftwareModule> getSoftwareModule(long moduleId);
|
||||
|
||||
/**
|
||||
* Retrieves {@link SoftwareModuleMetadata} where {@link SoftwareModuleMetadata#isTargetVisible()}.
|
||||
* Retrieves software module metadata where isTargetVisible.
|
||||
*
|
||||
* @param moduleId of the {@link SoftwareModule}
|
||||
* @return the map of software module id to {@link SoftwareModuleMetadata} with maximum size of
|
||||
* {@link RepositoryConstants#MAX_META_DATA_COUNT}
|
||||
* @return the map of software module id to software module metadata with maximum size of {@link RepositoryConstants#MAX_META_DATA_COUNT}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
Map<Long, List<SoftwareModuleMetadata>> findTargetVisibleMetaDataBySoftwareModuleId(@NotNull Collection<Long> moduleId);
|
||||
Map<Long, Map<String, String>> findTargetVisibleMetaDataBySoftwareModuleId(@NotNull Collection<Long> moduleId);
|
||||
|
||||
/**
|
||||
* Simple addition of a new {@link ActionStatus} entry to the {@link Action}. No state changes.
|
||||
|
||||
@@ -12,7 +12,6 @@ package org.eclipse.hawkbit.repository;
|
||||
import org.eclipse.hawkbit.repository.builder.ActionStatusBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutGroupBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TagBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
|
||||
@@ -31,11 +30,6 @@ public interface EntityFactory {
|
||||
*/
|
||||
ActionStatusBuilder actionStatus();
|
||||
|
||||
/**
|
||||
* @return {@link SoftwareModuleMetadataBuilder} object
|
||||
*/
|
||||
SoftwareModuleMetadataBuilder softwareModuleMetadata();
|
||||
|
||||
/**
|
||||
* @return {@link TagBuilder} object
|
||||
*/
|
||||
|
||||
@@ -9,14 +9,17 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
|
||||
/**
|
||||
* Repository constants.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class RepositoryConstants {
|
||||
|
||||
/**
|
||||
@@ -46,12 +49,7 @@ public final class RepositoryConstants {
|
||||
/**
|
||||
* Maximum number of metadata entries provided to controllers.
|
||||
*
|
||||
* @see SoftwareModuleMetadata#isTargetVisible()
|
||||
* @see SoftwareModule.MetadataValueCreate#isTargetVisible()
|
||||
*/
|
||||
public static final int MAX_META_DATA_COUNT = 50;
|
||||
|
||||
private RepositoryConstants() {
|
||||
// Utility class.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,7 +10,6 @@
|
||||
package org.eclipse.hawkbit.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -25,8 +24,6 @@ import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
@@ -34,9 +31,8 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.NamedVersionedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValue;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.Type;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
@@ -53,27 +49,27 @@ public interface SoftwareModuleManagement<T extends SoftwareModule>
|
||||
return "SOFTWARE_MODULE";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or updates a distribution set meta-data value.
|
||||
*
|
||||
* @param id the software module id which meta-data has to be updated
|
||||
* @param key the key of the meta-data entry to be updated
|
||||
* @param value the meta-data value to be updated
|
||||
* @throws EntityNotFoundException in case the meta-data entry does not exist and cannot be updated
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_UPDATE_REPOSITORY)
|
||||
void createMetadata(@NotNull Long id, @NotEmpty String key, @NotNull @Valid MetadataValue value);
|
||||
|
||||
/**
|
||||
* Creates a list of software module meta-data entries.
|
||||
*
|
||||
* @param metadata the meta-data entries to create
|
||||
* @throws EntityAlreadyExistsException in case one of the meta-data entry already exists for the specific key
|
||||
* @throws EntityNotFoundException if software module with given ID does not exist
|
||||
* @throws AssignmentQuotaExceededException if the maximum number of {@link SoftwareModuleMetadata} entries is exceeded for the addressed
|
||||
* {@link SoftwareModule}
|
||||
* @throws AssignmentQuotaExceededException if the maximum number of meta-data entries is exceeded for the addressed {@link SoftwareModule}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_UPDATE_REPOSITORY)
|
||||
void createMetadata(@NotNull @Valid Collection<SoftwareModuleMetadataCreate> metadata);
|
||||
|
||||
/**
|
||||
* Finds all meta-data by the given software module id.
|
||||
*
|
||||
* @param id the software module id to retrieve the meta-data from
|
||||
* @return a paged result of all meta-data entries for a given software module id
|
||||
* @throws EntityNotFoundException if software module with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
|
||||
List<SoftwareModuleMetadata> getMetadata(long id);
|
||||
void createMetadata(@NotNull Long id, @NotEmpty @Valid Map<String, ? extends MetadataValue> metadata);
|
||||
|
||||
/**
|
||||
* Finds all meta-data by the given software module id and key.
|
||||
@@ -84,52 +80,30 @@ public interface SoftwareModuleManagement<T extends SoftwareModule>
|
||||
* @throws EntityNotFoundException if software module with given ID does not exist ot the
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
|
||||
SoftwareModuleMetadata getMetadata(long id, String key);
|
||||
MetadataValue getMetadata(@NotNull Long id, @NotEmpty String key);
|
||||
|
||||
/**
|
||||
* Finds all meta-data by the given software module id where {@link SoftwareModuleMetadata#isTargetVisible()}.
|
||||
* Finds all meta-data by the given software module id.
|
||||
*
|
||||
* @param id the software module id to retrieve the meta-data from
|
||||
* @param pageable the page request to page the result
|
||||
* @return a paged result of all meta-data entries for a given software module id
|
||||
* @throws EntityNotFoundException if software module with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
|
||||
Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleIdAndTargetVisible(long id, @NotNull Pageable pageable);
|
||||
|
||||
/**
|
||||
* Creates or updates a single software module meta-data entry.
|
||||
*
|
||||
* @param metadata the meta-data entry to create
|
||||
* @return the updated or created software module meta-data entry
|
||||
* @throws EntityAlreadyExistsException in case the meta-data entry already exists for the specific key
|
||||
* @throws EntityNotFoundException if software module with given ID does not exist
|
||||
* @throws AssignmentQuotaExceededException if the maximum number of {@link SoftwareModuleMetadata}
|
||||
* entries is exceeded for the addressed {@link SoftwareModule}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_UPDATE_REPOSITORY)
|
||||
SoftwareModuleMetadata updateMetadata(@NotNull @Valid SoftwareModuleMetadataCreate metadata);
|
||||
|
||||
/**
|
||||
* Updates a distribution set meta-data value if corresponding entry exists.
|
||||
*
|
||||
* @param update the meta-data entry to be updated
|
||||
* @return the updated meta-data entry
|
||||
* @throws EntityNotFoundException in case the meta-data entry does not exist and cannot be updated
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_UPDATE_REPOSITORY)
|
||||
SoftwareModuleMetadata updateMetadata(@NotNull @Valid SoftwareModuleMetadataUpdate update);
|
||||
Map<String, MetadataValue> getMetadata(@NotNull Long id);
|
||||
|
||||
/**
|
||||
* Deletes a software module meta-data entry.
|
||||
*
|
||||
* @param id where meta-data has to be deleted
|
||||
* @param key of the meta-data element
|
||||
* @return true if really deleted, false if not
|
||||
* @throws EntityNotFoundException if software module with given ID does not exist or the key is not found
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_UPDATE_REPOSITORY)
|
||||
void deleteMetadata(long id, @NotEmpty String key);
|
||||
void deleteMetadata(@NotNull Long id, @NotEmpty String key);
|
||||
|
||||
@PreAuthorize(SpringEvalExpressions.IS_SYSTEM_CODE)
|
||||
Map<Long, Map<String, String>> findMetaDataBySoftwareModuleIdsAndTargetVisible(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* Locks a software module.
|
||||
@@ -198,9 +172,6 @@ public interface SoftwareModuleManagement<T extends SoftwareModule>
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
|
||||
Slice<T> findByType(long typeId, @NotNull Pageable pageable);
|
||||
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
|
||||
Map<Long, List<SoftwareModuleMetadata>> findMetaDataBySoftwareModuleIdsAndTargetVisible(Collection<Long> moduleIds);
|
||||
|
||||
/**
|
||||
* Returns count of all modules assigned to given {@link DistributionSet}.
|
||||
*
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
|
||||
/**
|
||||
* Builder for {@link SoftwareModuleMetadata}.
|
||||
*/
|
||||
public interface SoftwareModuleMetadataBuilder {
|
||||
|
||||
/**
|
||||
* @param softwareModuleId of the {@link SoftwareModule} the {@link SoftwareModuleMetadata} belongs to
|
||||
* @param key of {@link SoftwareModuleMetadata#getKey()}
|
||||
* @return builder instance
|
||||
*/
|
||||
SoftwareModuleMetadataUpdate update(long softwareModuleId, String key);
|
||||
|
||||
/**
|
||||
* @param softwareModuleId of the {@link SoftwareModule} the {@link SoftwareModuleMetadata} belongs to
|
||||
* @return builder instance
|
||||
*/
|
||||
SoftwareModuleMetadataCreate create(long softwareModuleId);
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.builder;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
|
||||
/**
|
||||
* Builder to create a new {@link SoftwareModuleMetadata} entry. Defines all
|
||||
* fields that can be set at creation time. Other fields are set by the
|
||||
* repository automatically, e.g. {@link BaseEntity#getCreatedAt()}.
|
||||
*/
|
||||
public interface SoftwareModuleMetadataCreate {
|
||||
|
||||
/**
|
||||
* @param key for {@link SoftwareModuleMetadata#getKey()}
|
||||
* @return updated builder instance
|
||||
*/
|
||||
SoftwareModuleMetadataCreate key(@Size(min = 1, max =SoftwareModule.METADATA_KEY_MAX_SIZE) @NotNull String key);
|
||||
|
||||
/**
|
||||
* @param value for {@link SoftwareModuleMetadata#getValue()}
|
||||
* @return updated builder instance
|
||||
*/
|
||||
SoftwareModuleMetadataCreate value(@Size(max = SoftwareModule.METADATA_VALUE_MAX_SIZE) String value);
|
||||
|
||||
/**
|
||||
* @param visible for {@link SoftwareModuleMetadata#isTargetVisible()}
|
||||
* @return updated builder instance
|
||||
*/
|
||||
SoftwareModuleMetadataCreate targetVisible(Boolean visible);
|
||||
|
||||
/**
|
||||
* @return peek on current state of {@link SoftwareModuleMetadata} in the
|
||||
* builder
|
||||
*/
|
||||
SoftwareModuleMetadata build();
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.builder;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
|
||||
/**
|
||||
* Builder to update an existing {@link SoftwareModuleMetadata} entry. Defines
|
||||
* all fields that can be updated.
|
||||
*/
|
||||
public interface SoftwareModuleMetadataUpdate {
|
||||
|
||||
/**
|
||||
* @param value for {@link SoftwareModuleMetadata#getValue()}
|
||||
* @return updated builder instance
|
||||
*/
|
||||
SoftwareModuleMetadataUpdate value(@Size(min = 1, max = SoftwareModule.METADATA_VALUE_MAX_SIZE) @NotNull String value);
|
||||
|
||||
/**
|
||||
* @param visible for {@link SoftwareModuleMetadata#isTargetVisible()}
|
||||
* @return updated builder instance
|
||||
*/
|
||||
SoftwareModuleMetadataUpdate targetVisible(Boolean visible);
|
||||
}
|
||||
@@ -12,6 +12,11 @@ package org.eclipse.hawkbit.repository.model;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Software package as sub element of a {@link DistributionSet}.
|
||||
*/
|
||||
@@ -81,4 +86,28 @@ public interface SoftwareModule extends NamedVersionedEntity {
|
||||
return getArtifacts().stream().filter(artifact -> artifact.getFilename().equalsIgnoreCase(fileName.trim()))
|
||||
.findAny();
|
||||
}
|
||||
|
||||
interface MetadataValue {
|
||||
|
||||
String getValue();
|
||||
boolean isTargetVisible();
|
||||
}
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
class MetadataValueCreate implements MetadataValue {
|
||||
|
||||
@Size(max = METADATA_VALUE_MAX_SIZE)
|
||||
private String value;
|
||||
private boolean targetVisible;
|
||||
|
||||
public MetadataValueCreate(final String value) {
|
||||
this(value, false);
|
||||
}
|
||||
|
||||
public MetadataValueCreate(final String value, final boolean targetVisible) {
|
||||
this.value = value;
|
||||
this.targetVisible = targetVisible;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Metadata element of a {@link SoftwareModule}. The software module metadata is not only (key, value) pair (like the metadata of
|
||||
* targets and distribution sets), but also contains the information if the metadata is visible for targets as part of {@link Action}.
|
||||
*/
|
||||
public interface SoftwareModuleMetadata extends Serializable {
|
||||
|
||||
/**
|
||||
* @return the key
|
||||
*/
|
||||
String getKey();
|
||||
|
||||
/**
|
||||
* @return the value
|
||||
*/
|
||||
String getValue();
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if element is visible for targets as part of {@link Action}.
|
||||
*/
|
||||
boolean isTargetVisible();
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.builder;
|
||||
|
||||
/**
|
||||
* Update implementation.
|
||||
*/
|
||||
public class GenericSoftwareModuleMetadataUpdate
|
||||
extends AbstractSoftwareModuleMetadataUpdateCreate<SoftwareModuleMetadataUpdate>
|
||||
implements SoftwareModuleMetadataUpdate {
|
||||
|
||||
public GenericSoftwareModuleMetadataUpdate(final long softwareModuleId, final String key) {
|
||||
super.softwareModuleId = softwareModuleId;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -149,17 +149,16 @@ public class SpecificationBuilder<T> {
|
||||
if (comparison.getValue() == null) {
|
||||
// map entry with key is null (doesn't exist) / is not null (exists) - use left join with on
|
||||
return switch (op) {
|
||||
case EQ -> cb.isNull(pathResolver.getJoinOn(attribute, split[1]));
|
||||
case NE -> cb.isNotNull(pathResolver.getJoinOn(attribute, split[1]));
|
||||
case EQ -> cb.isNull(toMapValuePath(pathResolver.getJoinOn(attribute, split[1])));
|
||||
case NE -> cb.isNotNull(toMapValuePath(pathResolver.getJoinOn(attribute, split[1])));
|
||||
default -> throw new RSQLParameterSyntaxException(
|
||||
String.format("Operator %s is not supported for map fields with value null", op));
|
||||
};
|
||||
} else {
|
||||
final MapJoin<?, ?, ?> mapPath = (MapJoin<?, ?, ?>) pathResolver.getPath(attribute);
|
||||
final Path<String> valuePath = (Path<String>) mapPath.value();
|
||||
return isNot(op)
|
||||
? compare(comparison, pathResolver.getJoinOnInner(attribute, split[1]))
|
||||
: cb.and(equal(mapPath.key(), split[1]), compare(comparison, valuePath));
|
||||
? compare(comparison, toMapValuePath(pathResolver.getJoinOnInner(attribute, split[1])))
|
||||
: cb.and(equal(mapPath.key(), split[1]), compare(comparison, toMapValuePath(mapPath)));
|
||||
}
|
||||
} else if (attribute instanceof SetAttribute<?, ?> setAttribute) {
|
||||
if (split.length < 2 || ObjectUtils.isEmpty(split[1])) {
|
||||
@@ -185,6 +184,12 @@ public class SpecificationBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Path<String> toMapValuePath(final Path<?> mapJoin) {
|
||||
final Path<?> valuePath = ((MapJoin<?, ?, ?>) mapJoin).value();
|
||||
return valuePath.getJavaType() == String.class ? (Path<String>) valuePath : valuePath.get("value");
|
||||
}
|
||||
|
||||
private Predicate compare(final Comparison comparison, final Path<?> fieldPath) {
|
||||
final List<Object> values = getValues(comparison, fieldPath.getJavaType());
|
||||
final Object firstValue = values.get(0);
|
||||
|
||||
@@ -343,8 +343,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
||||
|
||||
final Predicate mapPredicate = mapToMapPredicate(fieldPath, queryPath);
|
||||
|
||||
|
||||
final Predicate valuePredicate = addOperatorPredicate(node, fieldPath, transformedValues, value, queryPath);
|
||||
final Predicate valuePredicate = addOperatorPredicate(node, queryPath.getEnumValue().isMap() ? (Path)toMapValuePath(fieldPath) : fieldPath, transformedValues, value, queryPath);
|
||||
return toSingleList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
||||
}
|
||||
|
||||
@@ -380,6 +379,16 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Path<String> toMapValuePath(final Path<?> fieldPath) {
|
||||
final Path<?> mapValuePath = ((MapJoin<?, ?, ?>) pathOfString(fieldPath)).value();
|
||||
if (mapValuePath.getJavaType() == String.class) {
|
||||
return (Path<String>) mapValuePath;
|
||||
} else {
|
||||
return mapValuePath.get("value");
|
||||
}
|
||||
}
|
||||
|
||||
private Predicate getOutPredicate(
|
||||
final List<Object> transformedValues,
|
||||
final QueryPath queryPath, final Path<Object> fieldPath) {
|
||||
@@ -496,8 +505,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private Expression<String> getExpressionToCompare(final Path innerFieldPath, final A enumField) {
|
||||
if (enumField.isMap()){
|
||||
// Currently we support only string key. So below cast is safe.
|
||||
return (Expression<String>) (((MapJoin<?, ?, ?>) pathOfString(innerFieldPath)).value());
|
||||
return toMapValuePath(innerFieldPath);
|
||||
} else {
|
||||
return pathOfString(innerFieldPath);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
||||
if (values.get(0) == null) {
|
||||
// IS operator for maps and null value is treated as doesn't exist correspondingly
|
||||
((PluralJoin<?, ?, ?>) fieldPath).on(toMapEntryKeyPredicate(queryPath, fieldPath));
|
||||
return cb.isNull(fieldPath);
|
||||
return cb.isNull(toMapValuePath(fieldPath));
|
||||
}
|
||||
} else if (node.getOperator() == NOT) {
|
||||
if (values.size() != 1) {
|
||||
@@ -139,10 +139,10 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
||||
((PluralJoin<?, ?, ?>) fieldPath).on(toMapEntryKeyPredicate(queryPath, fieldPath));
|
||||
if (values.get(0) == null) {
|
||||
// special handling of "exists"
|
||||
return cb.isNotNull(fieldPath);
|
||||
return cb.isNotNull(toMapValuePath(fieldPath));
|
||||
} else {
|
||||
// special handling or "not equal" or null (same as != but with possible optimized join - no subquery)
|
||||
return toNotEqualToPredicate(queryPath, fieldPath, values.get(0));
|
||||
return toNotEqualToPredicate(queryPath, toMapValuePath(fieldPath), values.get(0));
|
||||
}
|
||||
}
|
||||
mapEntryKeyPredicate = toMapEntryKeyPredicate(queryPath, fieldPath);
|
||||
@@ -150,11 +150,21 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
||||
mapEntryKeyPredicate = null;
|
||||
}
|
||||
|
||||
final Predicate valuePredicate = toOperatorAndValuePredicate(node, queryPath, fieldPath, values);
|
||||
final Predicate valuePredicate = toOperatorAndValuePredicate(node, queryPath, queryPath.getEnumValue().isMap() ? toMapValuePath(fieldPath) : fieldPath, values);
|
||||
|
||||
return mapEntryKeyPredicate == null ? valuePredicate : cb.and(mapEntryKeyPredicate, valuePredicate);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Path<String> toMapValuePath(final Path<?> fieldPath) {
|
||||
final Path<?> mapValuePath = ((MapJoin<?, ?, ?>) pathOfString(fieldPath)).value();
|
||||
if (mapValuePath.getJavaType() == String.class) {
|
||||
return (Path<String>) mapValuePath;
|
||||
} else {
|
||||
return mapValuePath.get("value");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Predicate toMapEntryKeyPredicate(final QueryPath queryPath, final Path<?> fieldPath) {
|
||||
final String[] graph = queryPath.getJpaPath();
|
||||
@@ -341,7 +351,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
||||
private Path<String> getExpressionToCompare(final A enumField, final Path fieldPath) {
|
||||
if (enumField.isMap()) {
|
||||
// Currently we support only string key. So below cast is safe.
|
||||
return (Path<String>) (((MapJoin<?, ?, ?>) fieldPath).value());
|
||||
return toMapValuePath(fieldPath);
|
||||
} else {
|
||||
return pathOfString(fieldPath);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.ActionStatusBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutGroupBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TagBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
|
||||
@@ -33,19 +32,16 @@ public class JpaEntityFactory implements EntityFactory {
|
||||
private final TargetBuilder targetBuilder;
|
||||
private final TargetTypeBuilder targetTypeBuilder;
|
||||
private final TargetFilterQueryBuilder targetFilterQueryBuilder;
|
||||
private final SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder;
|
||||
private final RolloutBuilder rolloutBuilder;
|
||||
|
||||
@SuppressWarnings("java:S107")
|
||||
public JpaEntityFactory(
|
||||
final TargetBuilder targetBuilder, final TargetTypeBuilder targetTypeBuilder,
|
||||
final TargetFilterQueryBuilder targetFilterQueryBuilder,
|
||||
final SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder,
|
||||
final RolloutBuilder rolloutBuilder) {
|
||||
this.targetBuilder = targetBuilder;
|
||||
this.targetTypeBuilder = targetTypeBuilder;
|
||||
this.targetFilterQueryBuilder = targetFilterQueryBuilder;
|
||||
this.softwareModuleMetadataBuilder = softwareModuleMetadataBuilder;
|
||||
this.rolloutBuilder = rolloutBuilder;
|
||||
}
|
||||
@Override
|
||||
@@ -53,11 +49,6 @@ public class JpaEntityFactory implements EntityFactory {
|
||||
return new JpaActionStatusBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftwareModuleMetadataBuilder softwareModuleMetadata() {
|
||||
return softwareModuleMetadataBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagBuilder<Tag> tag() {
|
||||
return (TagBuilder)new JpaTagBuilder();
|
||||
|
||||
@@ -44,7 +44,6 @@ import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionSecr
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeBuilder;
|
||||
@@ -60,7 +59,6 @@ import org.eclipse.hawkbit.repository.jpa.autocleanup.AutoActionCleanup;
|
||||
import org.eclipse.hawkbit.repository.jpa.autocleanup.AutoCleanupScheduler;
|
||||
import org.eclipse.hawkbit.repository.jpa.autocleanup.CleanupTask;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleMetadataBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetFilterQueryBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetTypeBuilder;
|
||||
@@ -70,7 +68,6 @@ import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitDefaultServiceExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
@@ -323,12 +320,6 @@ public class JpaRepositoryConfiguration {
|
||||
return new JpaTargetTypeBuilder(dsTypeManagement);
|
||||
}
|
||||
|
||||
@Bean
|
||||
SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder(
|
||||
final JpaSoftwareModuleManagement softwareModuleManagement) {
|
||||
return new JpaSoftwareModuleMetadataBuilder(softwareModuleManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param distributionSetManagement for loading {@link Rollout#getDistributionSet()}
|
||||
* @return RolloutBuilder bean
|
||||
@@ -461,11 +452,9 @@ public class JpaRepositoryConfiguration {
|
||||
EntityFactory entityFactory(
|
||||
final TargetBuilder targetBuilder, final TargetTypeBuilder targetTypeBuilder,
|
||||
final TargetFilterQueryBuilder targetFilterQueryBuilder,
|
||||
final SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder,
|
||||
final RolloutBuilder rolloutBuilder) {
|
||||
return new JpaEntityFactory(
|
||||
targetBuilder, targetTypeBuilder, targetFilterQueryBuilder,
|
||||
softwareModuleMetadataBuilder, rolloutBuilder);
|
||||
targetBuilder, targetTypeBuilder, targetFilterQueryBuilder, rolloutBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.builder.GenericSoftwareModuleMetadataUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
|
||||
/**
|
||||
* Builder implementation for {@link SoftwareModuleMetadata}.
|
||||
*/
|
||||
public class JpaSoftwareModuleMetadataBuilder implements SoftwareModuleMetadataBuilder {
|
||||
|
||||
private final JpaSoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
public JpaSoftwareModuleMetadataBuilder(final JpaSoftwareModuleManagement softwareModuleManagement) {
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftwareModuleMetadataUpdate update(final long softwareModuleId, final String key) {
|
||||
return new GenericSoftwareModuleMetadataUpdate(softwareModuleId, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftwareModuleMetadataCreate create(final long softwareModuleId) {
|
||||
return new JpaSoftwareModuleMetadataCreate(softwareModuleId, softwareModuleManagement);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractSoftwareModuleMetadataUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
|
||||
/**
|
||||
* Create/build implementation.
|
||||
*/
|
||||
public class JpaSoftwareModuleMetadataCreate
|
||||
extends AbstractSoftwareModuleMetadataUpdateCreate<SoftwareModuleMetadataCreate> implements SoftwareModuleMetadataCreate {
|
||||
|
||||
private final JpaSoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
JpaSoftwareModuleMetadataCreate(final long softwareModuleId, final JpaSoftwareModuleManagement softwareModuleManagement) {
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.softwareModuleId = softwareModuleId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaSoftwareModuleMetadata build() {
|
||||
final JpaSoftwareModule module = softwareModuleManagement.get(softwareModuleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, softwareModuleId));
|
||||
|
||||
if (key == null) {
|
||||
new JpaSoftwareModuleMetadata(key, module, value, isTargetVisible().orElse(false));
|
||||
}
|
||||
|
||||
return new JpaSoftwareModuleMetadata(key, module, value, isTargetVisible().orElse(false));
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.UpdateMode;
|
||||
@@ -82,7 +83,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.ql.EntityMatcher;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
|
||||
@@ -96,7 +96,6 @@ import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
@@ -143,7 +142,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
private final DeploymentManagement deploymentManagement;
|
||||
private final ConfirmationManagement confirmationManagement;
|
||||
private final SoftwareModuleRepository softwareModuleRepository;
|
||||
private final SoftwareModuleMetadataRepository softwareModuleMetadataRepository;
|
||||
private final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement;
|
||||
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private final ControllerPollProperties controllerPollProperties;
|
||||
@@ -162,7 +161,8 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
final RepositoryProperties repositoryProperties,
|
||||
final TargetRepository targetRepository, final TargetTypeManagement targetTypeManagement,
|
||||
final DeploymentManagement deploymentManagement, final ConfirmationManagement confirmationManagement,
|
||||
final SoftwareModuleRepository softwareModuleRepository, final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement,
|
||||
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final ControllerPollProperties controllerPollProperties,
|
||||
final PlatformTransactionManager txManager, final EntityFactory entityFactory, final EntityManager entityManager,
|
||||
@@ -176,7 +176,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.confirmationManagement = confirmationManagement;
|
||||
this.softwareModuleRepository = softwareModuleRepository;
|
||||
this.softwareModuleMetadataRepository = softwareModuleMetadataRepository;
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
this.controllerPollProperties = controllerPollProperties;
|
||||
@@ -281,11 +281,8 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, List<SoftwareModuleMetadata>> findTargetVisibleMetaDataBySoftwareModuleId(final Collection<Long> moduleId) {
|
||||
return softwareModuleMetadataRepository
|
||||
.findBySoftwareModuleIdInAndTargetVisible(moduleId, true, PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT))
|
||||
.getContent().stream()
|
||||
.collect(Collectors.groupingBy(o -> (Long) o[0], Collectors.mapping(o -> (SoftwareModuleMetadata) o[1], Collectors.toList())));
|
||||
public Map<Long, Map<String, String>> findTargetVisibleMetaDataBySoftwareModuleId(final Collection<Long> moduleId) {
|
||||
return systemSecurityContext.runAsSystem(() -> softwareModuleManagement.findMetaDataBySoftwareModuleIdsAndTargetVisible(moduleId));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,37 +15,30 @@ import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_M
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericSoftwareModuleMetadataUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.LockedException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule.JpaMetadataValue;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification;
|
||||
@@ -53,12 +46,12 @@ import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValue;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.utils.ObjectCopyUtil;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
@@ -71,13 +64,13 @@ import org.springframework.util.ObjectUtils;
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "software-module-management" }, matchIfMissing = true)
|
||||
public class JpaSoftwareModuleManagement
|
||||
extends AbstractJpaRepositoryManagement<JpaSoftwareModule, SoftwareModuleManagement.Create, SoftwareModuleManagement.Update, SoftwareModuleRepository, SoftwareModuleFields>
|
||||
extends
|
||||
AbstractJpaRepositoryManagement<JpaSoftwareModule, SoftwareModuleManagement.Create, SoftwareModuleManagement.Update, SoftwareModuleRepository, SoftwareModuleFields>
|
||||
implements SoftwareModuleManagement<JpaSoftwareModule> {
|
||||
|
||||
protected static final String SOFTWARE_MODULE_METADATA = "SoftwareModuleMetadata";
|
||||
|
||||
private final DistributionSetRepository distributionSetRepository;
|
||||
private final SoftwareModuleMetadataRepository softwareModuleMetadataRepository;
|
||||
private final SoftwareModuleTypeRepository softwareModuleTypeRepository;
|
||||
private final ArtifactManagement artifactManagement;
|
||||
private final QuotaManagement quotaManagement;
|
||||
@@ -86,12 +79,10 @@ public class JpaSoftwareModuleManagement
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final EntityManager entityManager,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement) {
|
||||
super(softwareModuleRepository, entityManager);
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
this.softwareModuleMetadataRepository = softwareModuleMetadataRepository;
|
||||
this.softwareModuleTypeRepository = softwareModuleTypeRepository;
|
||||
this.artifactManagement = artifactManagement;
|
||||
this.quotaManagement = quotaManagement;
|
||||
@@ -176,86 +167,97 @@ public class JpaSoftwareModuleManagement
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void createMetadata(final Collection<SoftwareModuleMetadataCreate> create) {
|
||||
// group by software module id to minimize database access
|
||||
create.stream()
|
||||
.map(JpaSoftwareModuleMetadataCreate.class::cast)
|
||||
.collect(Collectors.groupingBy(JpaSoftwareModuleMetadataCreate::getSoftwareModuleId))
|
||||
.forEach((id, createsForSoftwareModule) -> {
|
||||
assertSoftwareModuleExists(id);
|
||||
assertMetadataQuota(id, createsForSoftwareModule.size());
|
||||
|
||||
// touch to update revision and last modified timestamp
|
||||
JpaManagementHelper.touch(
|
||||
entityManager, jpaRepository, jpaRepository.findById(id).orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id)));
|
||||
createsForSoftwareModule.forEach(this::saveMetadata);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public List<SoftwareModuleMetadata> getMetadata(final long id) {
|
||||
assertSoftwareModuleExists(id);
|
||||
return (List) softwareModuleMetadataRepository.findAll(metadataBySoftwareModuleIdSpec(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftwareModuleMetadata getMetadata(final long id, final String key) {
|
||||
assertSoftwareModuleExists(id);
|
||||
|
||||
return findMetadata(id, key).orElseThrow(() -> new EntityNotFoundException(SOFTWARE_MODULE_METADATA, id + ":" + key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleIdAndTargetVisible(final long id, final Pageable pageable) {
|
||||
assertSoftwareModuleExists(id);
|
||||
return JpaManagementHelper.convertPage(softwareModuleMetadataRepository.findBySoftwareModuleIdAndTargetVisible(
|
||||
id, true, PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT)), pageable);
|
||||
public void createMetadata(final Long id, final String key, final MetadataValue value) {
|
||||
final JpaSoftwareModule softwareModule = jpaRepository
|
||||
.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id));
|
||||
final Map<String, JpaMetadataValue> metadataValueMap = softwareModule.getMetadata();
|
||||
final JpaMetadataValue existingValue = metadataValueMap.get(key);
|
||||
if (existingValue == null) {
|
||||
assertMetadataQuota(metadataValueMap.size() + 1L);
|
||||
}
|
||||
final JpaMetadataValue jpaMetadataValue = existingValue == null ?
|
||||
new JpaMetadataValue() : existingValue;
|
||||
if (ObjectCopyUtil.copy(value, jpaMetadataValue, true, UnaryOperator.identity())) {
|
||||
metadataValueMap.put(key, jpaMetadataValue);
|
||||
jpaRepository.save(softwareModule);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public SoftwareModuleMetadata updateMetadata(final SoftwareModuleMetadataCreate c) {
|
||||
final JpaSoftwareModuleMetadataCreate create = (JpaSoftwareModuleMetadataCreate) c;
|
||||
final Long id = create.getSoftwareModuleId();
|
||||
public void createMetadata(final Long id, final Map<String, ? extends MetadataValue> metadata) {
|
||||
final JpaSoftwareModule softwareModule = jpaRepository
|
||||
.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id));
|
||||
final Map<String, JpaMetadataValue> metadataValueMap = softwareModule.getMetadata();
|
||||
assertMetadataQuota(metadata.keySet().stream().filter(key -> !metadataValueMap.containsKey(key)).count() + metadataValueMap.size());
|
||||
final AtomicBoolean changed = new AtomicBoolean(false);
|
||||
metadata.forEach((key, value) -> {
|
||||
final JpaMetadataValue jpaMetadataValue = metadataValueMap.getOrDefault(key, new JpaMetadataValue());
|
||||
if (ObjectCopyUtil.copy(value, jpaMetadataValue, true, UnaryOperator.identity())) {
|
||||
metadataValueMap.put(key, jpaMetadataValue);
|
||||
changed.set(true);
|
||||
}
|
||||
});
|
||||
if (changed.get()) {
|
||||
jpaRepository.save(softwareModule);
|
||||
}
|
||||
}
|
||||
|
||||
assertSoftwareModuleExists(id);
|
||||
assertMetadataQuota(id, 1);
|
||||
@Override
|
||||
public MetadataValue getMetadata(final Long id, final String key) {
|
||||
final JpaSoftwareModule softwareModule = jpaRepository
|
||||
.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id));
|
||||
final MetadataValue metadataValue = softwareModule.getMetadata().get(key);
|
||||
if (metadataValue == null) {
|
||||
throw new EntityNotFoundException(SOFTWARE_MODULE_METADATA, id + ":" + key);
|
||||
} else {
|
||||
return metadataValue;
|
||||
}
|
||||
}
|
||||
|
||||
// touch to update revision and last modified timestamp
|
||||
JpaManagementHelper.touch(
|
||||
entityManager, jpaRepository, jpaRepository.findById(id).orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id)));
|
||||
return saveMetadata(create);
|
||||
@Override
|
||||
public Map<String, MetadataValue> getMetadata(final Long id) {
|
||||
return jpaRepository
|
||||
.findById(id)
|
||||
.map(JpaSoftwareModule::getMetadata)
|
||||
.map(metadata -> metadata.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
e -> (MetadataValue)e.getValue())))
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public SoftwareModuleMetadata updateMetadata(final SoftwareModuleMetadataUpdate u) {
|
||||
final GenericSoftwareModuleMetadataUpdate update = (GenericSoftwareModuleMetadataUpdate) u;
|
||||
|
||||
// check if exists otherwise throw entity not found exception
|
||||
final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) findMetadata(
|
||||
update.getSoftwareModuleId(), update.getKey())
|
||||
.orElseThrow(() -> new EntityNotFoundException(SOFTWARE_MODULE_METADATA, update.getSoftwareModuleId() + ":" + update.getKey()));
|
||||
|
||||
update.getValue().ifPresent(metadata::setValue);
|
||||
update.isTargetVisible().ifPresent(metadata::setTargetVisible);
|
||||
|
||||
JpaManagementHelper.touch(entityManager, jpaRepository, metadata.getSoftwareModule());
|
||||
return softwareModuleMetadataRepository.save(metadata);
|
||||
public void deleteMetadata(final Long id, final String key) {
|
||||
final JpaSoftwareModule softwareModule = jpaRepository
|
||||
.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id));
|
||||
final Map<String, JpaMetadataValue> metadataValueMap = softwareModule.getMetadata();
|
||||
if (!metadataValueMap.containsKey(key)) {
|
||||
throw new EntityNotFoundException(SOFTWARE_MODULE_METADATA, id + ":" + key);
|
||||
}
|
||||
metadataValueMap.remove(key);
|
||||
jpaRepository.save(softwareModule);
|
||||
}
|
||||
|
||||
// called only with 'system code' access, so no need to check access control
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void deleteMetadata(final long id, final String key) {
|
||||
final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) findMetadata(id, key)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SOFTWARE_MODULE_METADATA, id + ":" + key));
|
||||
|
||||
JpaManagementHelper.touch(entityManager, jpaRepository, metadata.getSoftwareModule());
|
||||
softwareModuleMetadataRepository.deleteById(metadata.getId());
|
||||
public Map<Long, Map<String, String>> findMetaDataBySoftwareModuleIdsAndTargetVisible(final Collection<Long> ids) {
|
||||
return jpaRepository.findVisibleMetadataByModuleIds(ids)
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
entry -> (Long) entry[0],
|
||||
Collectors.toMap(
|
||||
entry -> (String) entry[1],
|
||||
entry -> (String) entry[2],
|
||||
(existing, replacement) -> existing, // in case of duplicates, keep the first one
|
||||
HashMap::new)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -340,14 +342,6 @@ public class JpaSoftwareModuleManagement
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, List<SoftwareModuleMetadata>> findMetaDataBySoftwareModuleIdsAndTargetVisible(final Collection<Long> moduleIds) {
|
||||
return softwareModuleMetadataRepository
|
||||
.findBySoftwareModuleIdInAndTargetVisible(moduleIds, true, PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT))
|
||||
.getContent().stream()
|
||||
.collect(Collectors.groupingBy(o -> (Long) o[0], Collectors.mapping(o -> (SoftwareModuleMetadata) o[1], Collectors.toList())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByAssignedTo(final long distributionSetId) {
|
||||
assertDistributionSetExists(distributionSetId);
|
||||
@@ -355,10 +349,6 @@ public class JpaSoftwareModuleManagement
|
||||
return jpaRepository.count(SoftwareModuleSpecification.byAssignedToDs(distributionSetId));
|
||||
}
|
||||
|
||||
private static Specification<JpaSoftwareModuleMetadata> metadataBySoftwareModuleIdSpec(final long id) {
|
||||
return (root, query, cb) -> cb.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule).get(AbstractJpaBaseEntity_.id), id);
|
||||
}
|
||||
|
||||
private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) {
|
||||
jpaRepository.getAccessController().ifPresent(accessController ->
|
||||
accessController.assertOperationAllowed(AccessController.Operation.DELETE, swModule));
|
||||
@@ -374,41 +364,14 @@ public class JpaSoftwareModuleManagement
|
||||
smFilterNameAndVersionEntries[1]);
|
||||
}
|
||||
|
||||
private SoftwareModuleMetadata saveMetadata(final JpaSoftwareModuleMetadataCreate create) {
|
||||
assertSoftwareModuleMetadataDoesNotExist(create.getSoftwareModuleId(), create);
|
||||
return softwareModuleMetadataRepository.save(create.build());
|
||||
}
|
||||
|
||||
private Optional<SoftwareModuleMetadata> findMetadata(final long id, final String key) {
|
||||
assertSoftwareModuleExists(id);
|
||||
|
||||
return softwareModuleMetadataRepository.findById(new SwMetadataCompositeKey(id, key))
|
||||
.map(SoftwareModuleMetadata.class::cast);
|
||||
}
|
||||
|
||||
private void assertSoftwareModuleMetadataDoesNotExist(final Long id, final JpaSoftwareModuleMetadataCreate md) {
|
||||
if (softwareModuleMetadataRepository.existsById(new SwMetadataCompositeKey(id, md.getKey()))) {
|
||||
throw new EntityAlreadyExistsException("Metadata entry with key '" + md.getKey() + "' already exists!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the meta-data quota for the software module with the given ID.
|
||||
*
|
||||
* @param id The software module ID.
|
||||
* @param requested Number of meta-data entries to be created.
|
||||
*/
|
||||
private void assertMetadataQuota(final Long id, final int requested) {
|
||||
private void assertMetadataQuota(final long requested) {
|
||||
final int maxMetaData = quotaManagement.getMaxMetaDataEntriesPerSoftwareModule();
|
||||
QuotaHelper.assertAssignmentQuota(
|
||||
id, requested, maxMetaData, SoftwareModuleMetadata.class, SoftwareModule.class,
|
||||
softwareModuleMetadataRepository::countBySoftwareModuleId);
|
||||
}
|
||||
|
||||
private void assertSoftwareModuleExists(final Long id) {
|
||||
if (!jpaRepository.existsById(id)) {
|
||||
throw new EntityNotFoundException(SoftwareModule.class, id);
|
||||
}
|
||||
QuotaHelper.assertAssignmentQuota(requested, maxMetaData, SoftwareModule.MetadataValueCreate.class, SoftwareModule.class);
|
||||
}
|
||||
|
||||
private void assertSoftwareModuleTypeExists(final Long typeId) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
@@ -10,6 +10,7 @@
|
||||
package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -20,6 +21,7 @@ import jakarta.persistence.CollectionTable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.ConstraintMode;
|
||||
import jakarta.persistence.ElementCollection;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.ForeignKey;
|
||||
@@ -36,7 +38,7 @@ import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
@@ -102,8 +104,7 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
|
||||
joinColumns = { @JoinColumn(name = "sm", nullable = false) },
|
||||
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_sm_metadata_sm"))
|
||||
@MapKeyColumn(name = "meta_key", length = SoftwareModule.METADATA_KEY_MAX_SIZE)
|
||||
@Column(name = "meta_value", length = SoftwareModule.METADATA_VALUE_MAX_SIZE)
|
||||
private Map<String, String> metadata;
|
||||
private Map<String, JpaMetadataValue> metadata;
|
||||
|
||||
@Column(name = "locked")
|
||||
private boolean locked;
|
||||
@@ -192,4 +193,18 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
|
||||
public void fireDeleteEvent() {
|
||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new SoftwareModuleDeletedEvent(getTenant(), getId(), getClass()));
|
||||
}
|
||||
|
||||
@Data
|
||||
@Embeddable
|
||||
public static class JpaMetadataValue implements MetadataValue, Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "meta_value", length = SoftwareModule.METADATA_VALUE_MAX_SIZE)
|
||||
@Size(max = METADATA_VALUE_MAX_SIZE)
|
||||
private String value;
|
||||
@Column(name = "target_visible")
|
||||
private boolean targetVisible;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.ConstraintMode;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.ForeignKey;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.IdClass;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
|
||||
/**
|
||||
* Metadata for {@link SoftwareModule}.
|
||||
*/
|
||||
@NoArgsConstructor // Default constructor for JPA
|
||||
@Data
|
||||
@IdClass(SwMetadataCompositeKey.class)
|
||||
@Entity
|
||||
@Table(name = "sp_sm_metadata")
|
||||
public class JpaSoftwareModuleMetadata implements SoftwareModuleMetadata {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||
@JoinColumn(
|
||||
name = "sm", nullable = false, updatable = false,
|
||||
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_sm_metadata_sm"))
|
||||
private JpaSoftwareModule softwareModule;
|
||||
|
||||
@Id
|
||||
@Column(name = "meta_key", nullable = false, length = SoftwareModule.METADATA_KEY_MAX_SIZE, updatable = false)
|
||||
@Size(min = 1, max = SoftwareModule.METADATA_KEY_MAX_SIZE)
|
||||
@NotNull
|
||||
private String key;
|
||||
|
||||
@Column(name = "meta_value", length = SoftwareModule.METADATA_VALUE_MAX_SIZE)
|
||||
@Size(max = SoftwareModule.METADATA_VALUE_MAX_SIZE)
|
||||
@Basic
|
||||
private String value;
|
||||
|
||||
@Column(name = "target_visible")
|
||||
private boolean targetVisible;
|
||||
|
||||
public JpaSoftwareModuleMetadata(final String key, final SoftwareModule softwareModule, final String value) {
|
||||
this(key, softwareModule, value, false);
|
||||
}
|
||||
|
||||
public JpaSoftwareModuleMetadata(final String key, final SoftwareModule softwareModule, final String value, final boolean targetVisible) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.softwareModule = (JpaSoftwareModule) softwareModule;
|
||||
this.targetVisible = targetVisible;
|
||||
}
|
||||
|
||||
public SwMetadataCompositeKey getId() {
|
||||
return new SwMetadataCompositeKey(softwareModule.getId(), getKey());
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* The Software Module meta-data composite key which contains the meta-data key and the ID of the software module itself.
|
||||
*/
|
||||
@NoArgsConstructor // Default constructor for JPA
|
||||
@Data
|
||||
public final class SwMetadataCompositeKey implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String key;
|
||||
private Long softwareModule;
|
||||
|
||||
/**
|
||||
* @param moduleId the software module for this meta-data
|
||||
* @param key the key of the meta-data
|
||||
*/
|
||||
public SwMetadataCompositeKey(final Long moduleId, final String key) {
|
||||
this.softwareModule = moduleId;
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link SoftwareModuleMetadata} repository.
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface SoftwareModuleMetadataRepository
|
||||
extends PagingAndSortingRepository<JpaSoftwareModuleMetadata, SwMetadataCompositeKey>,
|
||||
CrudRepository<JpaSoftwareModuleMetadata, SwMetadataCompositeKey>,
|
||||
JpaSpecificationExecutor<JpaSoftwareModuleMetadata> {
|
||||
|
||||
/**
|
||||
* Locates the meta-data entries that match the given software module ID and target visibility flag.
|
||||
*
|
||||
* @param moduleId The ID of the software module.
|
||||
* @param targetVisible The target visibility flag.
|
||||
* @param page The pagination parameters.
|
||||
* @return A {@link Page} with the matching meta-data entries.
|
||||
*/
|
||||
Page<JpaSoftwareModuleMetadata> findBySoftwareModuleIdAndTargetVisible(
|
||||
@Param("moduleId") Long moduleId, @Param("targetVisible") boolean targetVisible, Pageable page);
|
||||
|
||||
/**
|
||||
* Locates the meta-data entries that match the given software module IDs and target visibility flag.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param moduleId List of software module IDs.
|
||||
* @param targetVisible The target visibility flag.
|
||||
* @param page The pagination parameters.
|
||||
* @return A {@link Page} with the matching meta-data entries.
|
||||
*/
|
||||
@Query("SELECT smd.softwareModule.id, smd FROM JpaSoftwareModuleMetadata smd WHERE smd.softwareModule.id IN :moduleId AND smd.targetVisible = :targetVisible")
|
||||
Page<Object[]> findBySoftwareModuleIdInAndTargetVisible(
|
||||
@Param("moduleId") Collection<Long> moduleId, @Param("targetVisible") boolean targetVisible, Pageable page);
|
||||
|
||||
/**
|
||||
* Counts the meta-data entries that are associated with the addressed software module.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param moduleId The ID of the software module.
|
||||
* @return The number of meta-data entries associated with the software module.
|
||||
*/
|
||||
long countBySoftwareModuleId(@Param("moduleId") Long moduleId);
|
||||
}
|
||||
@@ -9,6 +9,9 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
@@ -47,6 +50,9 @@ public interface SoftwareModuleRepository extends BaseEntityRepository<JpaSoftwa
|
||||
*/
|
||||
long countByAssignedToId(Long distributionSetId);
|
||||
|
||||
@Query("SELECT sm.id, KEY(m), m.value FROM JpaSoftwareModule sm JOIN sm.metadata m WHERE sm.id IN :ids AND m.targetVisible = true")
|
||||
List<Object[]> findVisibleMetadataByModuleIds(@Param("ids") Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety
|
||||
* reasons (this is a "delete everything" query after all) we add the tenant
|
||||
|
||||
@@ -44,7 +44,6 @@ import org.eclipse.hawkbit.repository.jpa.repository.LocalArtifactRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutTargetGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
@@ -111,8 +110,6 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
|
||||
@Autowired
|
||||
protected DistributionSetTagRepository distributionSetTagRepository;
|
||||
@Autowired
|
||||
protected SoftwareModuleMetadataRepository softwareModuleMetadataRepository;
|
||||
@Autowired
|
||||
protected ActionStatusRepository actionStatusRepository;
|
||||
@Autowired
|
||||
protected LocalArtifactRepository artifactRepository;
|
||||
|
||||
@@ -73,7 +73,6 @@ import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
@@ -989,7 +988,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
final DistributionSet set = testdataFactory.createDistributionSet();
|
||||
testdataFactory.addSoftwareModuleMetadata(set);
|
||||
|
||||
final Map<Long, List<SoftwareModuleMetadata>> result = controllerManagement
|
||||
final Map<Long, Map<String, String>> result = controllerManagement
|
||||
.findTargetVisibleMetaDataBySoftwareModuleId(set.getModules().stream().map(SoftwareModule::getId).toList());
|
||||
|
||||
assertThat(result).hasSize(3);
|
||||
|
||||
@@ -10,12 +10,15 @@
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.im.authentication.SpRole;
|
||||
import org.eclipse.hawkbit.repository.RepositoryManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractRepositoryManagementSecurityTest;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValueCreate;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
@@ -46,11 +49,15 @@ class SoftwareManagementSecurityTest
|
||||
@Test
|
||||
void createMetaDataPermissionsCheck() {
|
||||
assertPermissions(
|
||||
() -> softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(1L).key("key").value("value")),
|
||||
() -> {
|
||||
softwareModuleManagement.createMetadata(1L, "key", new MetadataValueCreate("value"));
|
||||
return null;
|
||||
},
|
||||
List.of(SpPermission.UPDATE_REPOSITORY));
|
||||
assertPermissions(() -> {
|
||||
softwareModuleManagement.createMetadata(
|
||||
List.of(entityFactory.softwareModuleMetadata().create(1L).key("key").value("value")));
|
||||
1L,
|
||||
Map.of("key", new MetadataValueCreate("value")));
|
||||
return null;
|
||||
}, List.of(SpPermission.UPDATE_REPOSITORY));
|
||||
}
|
||||
@@ -112,15 +119,6 @@ class SoftwareManagementSecurityTest
|
||||
assertPermissions(() -> softwareModuleManagement.getMetadata(1L), List.of(SpPermission.READ_REPOSITORY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests ManagementAPI PreAuthorized method with correct and insufficient permissions.
|
||||
*/
|
||||
@Test
|
||||
void findMetaDataBySoftwareModuleIdAndTargetVisiblePermissionsCheck() {
|
||||
assertPermissions(() -> softwareModuleManagement.findMetaDataBySoftwareModuleIdAndTargetVisible(1L, PAGE),
|
||||
List.of(SpPermission.READ_REPOSITORY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests ManagementAPI PreAuthorized method with correct and insufficient permissions.
|
||||
*/
|
||||
@@ -157,7 +155,10 @@ class SoftwareManagementSecurityTest
|
||||
@Test
|
||||
void updateMetaDataPermissionsCheck() {
|
||||
assertPermissions(
|
||||
() -> softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().update(1L, "key").value("value")),
|
||||
() -> {
|
||||
softwareModuleManagement.createMetadata(1L, "key", new MetadataValueCreate("value"));
|
||||
return null;
|
||||
},
|
||||
List.of(SpPermission.UPDATE_REPOSITORY));
|
||||
}
|
||||
|
||||
@@ -167,6 +168,6 @@ class SoftwareManagementSecurityTest
|
||||
@Test
|
||||
void findMetaDataBySoftwareModuleIdsAndTargetVisiblePermissionsCheck() {
|
||||
assertPermissions(() -> softwareModuleManagement.findMetaDataBySoftwareModuleIdsAndTargetVisible(List.of(1L)),
|
||||
List.of(SpPermission.READ_REPOSITORY));
|
||||
List.of(SpRole.SYSTEM_ROLE));
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,11 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -26,7 +26,6 @@ import jakarta.validation.ConstraintViolationException;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
@@ -37,7 +36,6 @@ import org.eclipse.hawkbit.repository.jpa.RandomGeneratedInputStream;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
@@ -45,7 +43,8 @@ import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValue;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValueCreate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
@@ -53,8 +52,6 @@ import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
||||
/**
|
||||
* Feature: Component Tests - Repository<br/>
|
||||
@@ -62,8 +59,6 @@ import org.springframework.data.domain.PageRequest;
|
||||
*/
|
||||
class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
private static final PageRequest PAGE_REQUEST_100 = PageRequest.of(0, 100);
|
||||
|
||||
/**
|
||||
* Verifies that management get access reacts as specified on calls for non existing entities by means
|
||||
* of Optional not present.
|
||||
@@ -72,14 +67,10 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
@ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) })
|
||||
void nonExistingEntityAccessReturnsNotPresent() {
|
||||
final SoftwareModule module = testdataFactory.createSoftwareModuleApp();
|
||||
|
||||
assertThat(softwareModuleManagement.get(1234L)).isNotPresent();
|
||||
|
||||
assertThat(softwareModuleManagement.findByNameAndVersionAndType(NOT_EXIST_ID, NOT_EXIST_ID, osType.getId()))
|
||||
.isNotPresent();
|
||||
|
||||
assertThatExceptionOfType(EntityNotFoundException.class)
|
||||
.isThrownBy(() -> softwareModuleManagement.getMetadata(module.getId(), NOT_EXIST_ID));
|
||||
assertThat(softwareModuleManagement.findByNameAndVersionAndType(NOT_EXIST_ID, NOT_EXIST_ID, osType.getId())).isNotPresent();
|
||||
final Long moduleId = module.getId();
|
||||
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(() -> softwareModuleManagement.getMetadata(moduleId, NOT_EXIST_ID));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,7 +80,7 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
@ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) })
|
||||
void entityQueriesReferringToNotExistingEntitiesThrowsException() {
|
||||
final SoftwareModule module = testdataFactory.createSoftwareModuleApp();
|
||||
testdataFactory.createSoftwareModuleApp();
|
||||
|
||||
final SoftwareModuleManagement.Create noType = SoftwareModuleManagement.Create.builder().name("xxx").type(null).build();
|
||||
final List<SoftwareModuleManagement.Create> noTypeList = List.of(noType);
|
||||
@@ -98,22 +89,20 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> softwareModuleManagement.create(noType));
|
||||
|
||||
verifyThrownExceptionBy(
|
||||
() -> softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().create(NOT_EXIST_IDL).key("xxx").value("xxx")), "SoftwareModule");
|
||||
() -> softwareModuleManagement.createMetadata(
|
||||
NOT_EXIST_IDL, "xxx", new MetadataValueCreate("xxx")), "SoftwareModule");
|
||||
verifyThrownExceptionBy(
|
||||
() -> softwareModuleManagement.createMetadata(Collections.singletonList(
|
||||
entityFactory.softwareModuleMetadata().create(NOT_EXIST_IDL).key("xxx").value("xxx"))), "SoftwareModule");
|
||||
() -> softwareModuleManagement.createMetadata(
|
||||
NOT_EXIST_IDL,
|
||||
Map.of("xxx", new MetadataValueCreate("xxx"))), "SoftwareModule");
|
||||
|
||||
verifyThrownExceptionBy(() -> softwareModuleManagement.delete(NOT_EXIST_IDL), "SoftwareModule");
|
||||
verifyThrownExceptionBy(() -> softwareModuleManagement.delete(Collections.singletonList(NOT_EXIST_IDL)), "SoftwareModule");
|
||||
verifyThrownExceptionBy(() -> softwareModuleManagement.deleteMetadata(NOT_EXIST_IDL, "xxx"), "SoftwareModule");
|
||||
|
||||
verifyThrownExceptionBy(
|
||||
() -> softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().update(NOT_EXIST_IDL, "xxx").value("xxx")), "SoftwareModule");
|
||||
verifyThrownExceptionBy(
|
||||
() -> softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().update(module.getId(), NOT_EXIST_ID).value("xxx")), "SoftwareModuleMetadata");
|
||||
() -> softwareModuleManagement.createMetadata(
|
||||
NOT_EXIST_IDL, "xxx", new MetadataValueCreate("xxx")), "SoftwareModule");
|
||||
|
||||
verifyThrownExceptionBy(() -> softwareModuleManagement.findByAssignedTo(NOT_EXIST_IDL, PAGE), "DistributionSet");
|
||||
|
||||
@@ -241,8 +230,8 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
testdataFactory.createSoftwareModuleApp();
|
||||
|
||||
assertThat((List) softwareModuleManagement.findByType(osType.getId(), PAGE).getContent())
|
||||
.as("Expected to find the following number of modules:").hasSize(2).as("with the following elements")
|
||||
.contains(two, one);
|
||||
.as("Expected to find the following number of modules:").hasSize(2)
|
||||
.as("with the following elements").contains(two, one);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -525,30 +514,21 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
assertThat(softwareModule.getOptLockRevision()).isEqualTo(1);
|
||||
|
||||
final SoftwareModuleMetadataCreate swMetadata1 = entityFactory.softwareModuleMetadata()
|
||||
.create(softwareModule.getId())
|
||||
.key(knownKey1)
|
||||
.value(knownValue1)
|
||||
.targetVisible(true);
|
||||
|
||||
final SoftwareModuleMetadataCreate swMetadata2 = entityFactory.softwareModuleMetadata()
|
||||
.create(softwareModule.getId())
|
||||
.key(knownKey2)
|
||||
.value(knownValue2);
|
||||
|
||||
softwareModuleManagement.createMetadata(Arrays.asList(swMetadata1, swMetadata2));
|
||||
softwareModuleManagement.createMetadata(
|
||||
softwareModule.getId(),
|
||||
Map.of(
|
||||
knownKey1, new MetadataValueCreate(knownValue1, true),
|
||||
knownKey2, new MetadataValueCreate(knownValue2)));
|
||||
|
||||
final SoftwareModule changedLockRevisionModule = softwareModuleManagement.get(softwareModule.getId()).get();
|
||||
assertThat(changedLockRevisionModule.getOptLockRevision()).isEqualTo(2);
|
||||
|
||||
assertThat(softwareModuleManagement.getMetadata(softwareModule.getId(), knownKey1)).satisfies(metadata -> {
|
||||
assertThat(metadata.getKey()).isEqualTo(knownKey1);
|
||||
assertThat(metadata.getValue()).isEqualTo(knownValue1);
|
||||
assertThat(metadata.isTargetVisible()).isTrue();
|
||||
});
|
||||
|
||||
assertThat(softwareModuleManagement.getMetadata(softwareModule.getId(), knownKey2)).satisfies(metadata -> {
|
||||
assertThat(metadata.getKey()).isEqualTo(knownKey2);
|
||||
assertThat(metadata.getValue()).isEqualTo(knownValue2);
|
||||
assertThat(metadata.isTargetVisible()).isFalse();
|
||||
});
|
||||
@@ -559,80 +539,49 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void createSoftwareModuleMetadataUntilQuotaIsExceeded() {
|
||||
|
||||
// add meta data one by one
|
||||
// add meta-data one by one
|
||||
final SoftwareModule module = testdataFactory.createSoftwareModuleApp("m1");
|
||||
final int maxMetaData = quotaManagement.getMaxMetaDataEntriesPerSoftwareModule();
|
||||
for (int i = 0; i < maxMetaData; ++i) {
|
||||
softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().create(module.getId()).key("k" + i).value("v" + i));
|
||||
softwareModuleManagement.createMetadata(module.getId(), "k" + i, new MetadataValueCreate("v" + i));
|
||||
}
|
||||
|
||||
// quota exceeded
|
||||
final SoftwareModuleMetadataCreate metadata = entityFactory.softwareModuleMetadata().create(module.getId())
|
||||
.key("k" + maxMetaData).value("v" + maxMetaData);
|
||||
final Long moduleId = module.getId();
|
||||
final MetadataValueCreate metadata = new MetadataValueCreate("v" + maxMetaData);
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
.isThrownBy(() -> softwareModuleManagement.updateMetadata(metadata));
|
||||
.isThrownBy(() -> softwareModuleManagement.createMetadata(moduleId, "k" + maxMetaData, metadata));
|
||||
|
||||
// add multiple meta data entries at once
|
||||
final SoftwareModule module2 = testdataFactory.createSoftwareModuleApp("m2");
|
||||
final List<SoftwareModuleMetadataCreate> create = new ArrayList<>();
|
||||
final Long moduleId2 = module2.getId();
|
||||
final Map<String, MetadataValueCreate> create = new HashMap<>();
|
||||
for (int i = 0; i < maxMetaData + 1; ++i) {
|
||||
create.add(entityFactory.softwareModuleMetadata().create(module2.getId()).key("k" + i).value("v" + i));
|
||||
create.put("k" + i, new MetadataValueCreate("v" + i));
|
||||
}
|
||||
// quota exceeded
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
.isThrownBy(() -> softwareModuleManagement.createMetadata(create));
|
||||
.isThrownBy(() -> softwareModuleManagement.createMetadata(moduleId2, create));
|
||||
|
||||
// add some meta data entries
|
||||
final SoftwareModule module3 = testdataFactory.createSoftwareModuleApp("m3");
|
||||
final int firstHalf = Math.round((maxMetaData) / 2.f);
|
||||
for (int i = 0; i < firstHalf; ++i) {
|
||||
softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().create(module3.getId()).key("k" + i).value("v" + i));
|
||||
softwareModuleManagement.createMetadata(module3.getId(), "k" + i, new MetadataValueCreate("v" + i));
|
||||
}
|
||||
// add too many data entries
|
||||
final Long moduleId3 = module3.getId();
|
||||
final int secondHalf = maxMetaData - firstHalf;
|
||||
final List<SoftwareModuleMetadataCreate> create2 = new ArrayList<>();
|
||||
final Map<String, MetadataValueCreate> create2 = new HashMap<>();
|
||||
for (int i = 0; i < secondHalf + 1; ++i) {
|
||||
create2.add(entityFactory.softwareModuleMetadata().create(module3.getId()).key("kk" + i).value("vv" + i));
|
||||
create2.put("kk" + i, new MetadataValueCreate("vv" + i));
|
||||
}
|
||||
// quota exceeded
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
.isThrownBy(() -> softwareModuleManagement.createMetadata(create2));
|
||||
.isThrownBy(() -> softwareModuleManagement.createMetadata(moduleId3, create2));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that metadata for a software module cannot be created for an existing key.
|
||||
*/
|
||||
@Test
|
||||
void createSoftwareModuleMetadataFailsIfKeyExists() {
|
||||
|
||||
final String knownKey1 = "myKnownKey1";
|
||||
final String knownValue1 = "myKnownValue1";
|
||||
final SoftwareModule ah = testdataFactory.createSoftwareModuleApp();
|
||||
|
||||
final SoftwareModuleMetadataCreate metadata = entityFactory.softwareModuleMetadata()
|
||||
.create(ah.getId()).key(knownKey1).value(knownValue1).targetVisible(true);
|
||||
softwareModuleManagement.updateMetadata(metadata);
|
||||
|
||||
assertThatExceptionOfType(EntityAlreadyExistsException.class)
|
||||
.isThrownBy(() -> softwareModuleManagement.updateMetadata(metadata))
|
||||
.withMessageContaining("Metadata").withMessageContaining(knownKey1);
|
||||
|
||||
final String knownKey2 = "myKnownKey2";
|
||||
|
||||
softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(ah.getId()).key(knownKey2)
|
||||
.value(knownValue1).targetVisible(false));
|
||||
|
||||
final SoftwareModuleMetadataCreate metadata2 = entityFactory.softwareModuleMetadata().create(ah.getId())
|
||||
.key(knownKey2).value(knownValue1).targetVisible(true);
|
||||
assertThatExceptionOfType(EntityAlreadyExistsException.class)
|
||||
.isThrownBy(() -> softwareModuleManagement.updateMetadata(metadata2))
|
||||
.withMessageContaining("Metadata").withMessageContaining(knownKey2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that metadata for a software module can be updated.
|
||||
*/
|
||||
@@ -649,8 +598,8 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(ah.getOptLockRevision()).isEqualTo(1);
|
||||
|
||||
// create an software module meta data entry
|
||||
final SoftwareModuleMetadata softwareModuleMetadata = softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().create(ah.getId()).key(knownKey).value(knownValue));
|
||||
softwareModuleManagement.createMetadata(ah.getId(), knownKey, new MetadataValueCreate(knownValue));
|
||||
final MetadataValue softwareModuleMetadata = softwareModuleManagement.getMetadata(ah.getId(), knownKey);
|
||||
assertThat(softwareModuleMetadata.isTargetVisible()).isFalse();
|
||||
assertThat(softwareModuleMetadata.getValue()).isEqualTo(knownValue);
|
||||
|
||||
@@ -660,8 +609,8 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(changedLockRevisionModule.getOptLockRevision()).isEqualTo(2);
|
||||
|
||||
// update the software module metadata
|
||||
final SoftwareModuleMetadata updated = softwareModuleManagement.updateMetadata(entityFactory
|
||||
.softwareModuleMetadata().update(ah.getId(), knownKey).value(knownUpdateValue).targetVisible(true));
|
||||
softwareModuleManagement.createMetadata(ah.getId(), knownKey, new MetadataValueCreate(knownUpdateValue, true));
|
||||
final MetadataValue updated = softwareModuleManagement.getMetadata(ah.getId(), knownKey);
|
||||
|
||||
// we are updating the sw metadata so also modifying the base software
|
||||
// module so opt lock revision must be two
|
||||
@@ -672,8 +621,6 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(updated).isNotNull();
|
||||
assertThat(updated.getValue()).isEqualTo(knownUpdateValue);
|
||||
assertThat(updated.isTargetVisible()).isTrue();
|
||||
assertThat(((JpaSoftwareModuleMetadata) updated).getId().getKey()).isEqualTo(knownKey);
|
||||
assertThat(((JpaSoftwareModuleMetadata) updated).getSoftwareModule().getId()).isEqualTo(ah.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -686,37 +633,18 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
final SoftwareModule swModule = testdataFactory.createSoftwareModuleApp();
|
||||
|
||||
softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().create(swModule.getId()).key(knownKey1).value(knownValue1));
|
||||
softwareModuleManagement.createMetadata(swModule.getId(), knownKey1, new MetadataValueCreate(knownValue1));
|
||||
|
||||
assertThat(softwareModuleManagement.getMetadata(swModule.getId()))
|
||||
assertThat(softwareModuleManagement.getMetadata(swModule.getId()).entrySet())
|
||||
.as("Contains the created metadata element").allSatisfy(metadata -> {
|
||||
assertThat(((JpaSoftwareModuleMetadata) metadata).getSoftwareModule().getId()).isEqualTo(swModule.getId());
|
||||
assertThat(metadata.getKey()).isEqualTo(knownKey1);
|
||||
assertThat(metadata.getValue()).isEqualTo(knownValue1);
|
||||
assertThat(metadata.getValue().getValue()).isEqualTo(knownValue1);
|
||||
});
|
||||
|
||||
softwareModuleManagement.deleteMetadata(swModule.getId(), knownKey1);
|
||||
assertThat(softwareModuleManagement.getMetadata(swModule.getId())).as("Metadata elements are").isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that non existing metadata find results in exception.
|
||||
*/
|
||||
@Test
|
||||
void findSoftwareModuleMetadataFailsIfEntryDoesNotExist() {
|
||||
final String knownKey1 = "myKnownKey1";
|
||||
final String knownValue1 = "myKnownValue1";
|
||||
|
||||
final SoftwareModule ah = testdataFactory.createSoftwareModuleApp();
|
||||
|
||||
softwareModuleManagement.updateMetadata(
|
||||
entityFactory.softwareModuleMetadata().create(ah.getId()).key(knownKey1).value(knownValue1));
|
||||
|
||||
assertThatExceptionOfType(EntityNotFoundException.class)
|
||||
.isThrownBy(() -> softwareModuleManagement.getMetadata(ah.getId(), "doesnotexist"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries and loads the metadata related to a given software module.
|
||||
*/
|
||||
@@ -729,28 +657,24 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
final int metadataCountSw2 = 10;
|
||||
|
||||
for (int index = 0; index < metadataCountSw1; index++) {
|
||||
softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(sw1.getId())
|
||||
.key("key" + index).value("value" + index).targetVisible(true));
|
||||
softwareModuleManagement.createMetadata(sw1.getId(), "key" + index, new MetadataValueCreate("value" + index, true));
|
||||
}
|
||||
|
||||
for (int index = 0; index < metadataCountSw2; index++) {
|
||||
softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(sw2.getId())
|
||||
.key("key" + index).value("value" + index).targetVisible(false));
|
||||
softwareModuleManagement.createMetadata(sw2.getId(), "key" + index, new MetadataValueCreate("value" + index, false));
|
||||
}
|
||||
|
||||
final List<SoftwareModuleMetadata> metadataSw1 = softwareModuleManagement.getMetadata(sw1.getId());
|
||||
final List<SoftwareModuleMetadata> metadataSw2 = softwareModuleManagement.getMetadata(sw2.getId());
|
||||
final Map<String, MetadataValue> metadataSw1 = softwareModuleManagement.getMetadata(sw1.getId());
|
||||
final Map<String, MetadataValue> metadataSw2 = softwareModuleManagement.getMetadata(sw2.getId());
|
||||
assertThat(metadataSw1).hasSize(metadataCountSw1);
|
||||
assertThat(metadataSw2).hasSize(metadataCountSw2);
|
||||
|
||||
final Page<SoftwareModuleMetadata> metadataSw1V = softwareModuleManagement.findMetaDataBySoftwareModuleIdAndTargetVisible(
|
||||
sw1.getId(), PAGE_REQUEST_100);
|
||||
final Page<SoftwareModuleMetadata> metadataSw2V = softwareModuleManagement.findMetaDataBySoftwareModuleIdAndTargetVisible(
|
||||
sw2.getId(), PAGE_REQUEST_100);
|
||||
assertThat(metadataSw1V.getNumberOfElements()).isEqualTo(metadataCountSw1);
|
||||
assertThat(metadataSw1V.getTotalElements()).isEqualTo(metadataCountSw1);
|
||||
assertThat(metadataSw2V.getNumberOfElements()).isZero();
|
||||
assertThat(metadataSw2V.getTotalElements()).isZero();
|
||||
final Map<String, String> metadataSw1V = softwareModuleManagement
|
||||
.findMetaDataBySoftwareModuleIdsAndTargetVisible(List.of(sw1.getId())).get(sw1.getId());
|
||||
final Map<String, String> metadataSw2V = softwareModuleManagement
|
||||
.findMetaDataBySoftwareModuleIdsAndTargetVisible(List.of(sw2.getId())).get(sw2.getId());
|
||||
assertThat(metadataSw1V).hasSize(metadataCountSw1);
|
||||
assertThat(metadataSw2V).isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,10 +13,10 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValueCreate;
|
||||
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -49,13 +49,8 @@ class RsqlSoftwareModuleFieldTest extends AbstractJpaIntegrationTest {
|
||||
final JpaSoftwareModule ah2 = (JpaSoftwareModule) softwareModuleManagement.create(
|
||||
SoftwareModuleManagement.Create.builder().type(appType).name("agent-hub2").version("1.0.1").description("agent-hub2").build());
|
||||
|
||||
final SoftwareModuleMetadataCreate softwareModuleMetadata = entityFactory.softwareModuleMetadata()
|
||||
.create(ah.getId()).key("metaKey").value("metaValue");
|
||||
softwareModuleManagement.updateMetadata(softwareModuleMetadata);
|
||||
|
||||
final SoftwareModuleMetadataCreate softwareModuleMetadata2 = entityFactory.softwareModuleMetadata()
|
||||
.create(ah2.getId()).key("metaKey").value("value");
|
||||
softwareModuleManagement.updateMetadata(softwareModuleMetadata2);
|
||||
softwareModuleManagement.createMetadata(ah.getId(), "metaKey", new MetadataValueCreate("metaValue"));
|
||||
softwareModuleManagement.createMetadata(ah2.getId(), "metaKey", new MetadataValueCreate("value"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,7 +155,6 @@ class RsqlSoftwareModuleFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey=in=(metaValue,value)", 2);
|
||||
assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey=out=(metaValue,notexist)", 1);
|
||||
assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".notExist==metaValue", 0);
|
||||
|
||||
}
|
||||
|
||||
private void assertRSQLQuery(final String rsql, final long expectedEntity) {
|
||||
|
||||
@@ -18,8 +18,10 @@ import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
|
||||
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaRepositoryConfiguration;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.ql.utils.HawkbitQlToSql;
|
||||
import org.eclipse.hawkbit.repository.test.TestConfiguration;
|
||||
@@ -45,6 +47,8 @@ class RsqlToSqlTest {
|
||||
|
||||
@Test
|
||||
void printPG() {
|
||||
printFrom(JpaSoftwareModule.class, SoftwareModuleFields.class, "metadata.x!=y");
|
||||
printFrom(JpaSoftwareModule.class, SoftwareModuleFields.class, "metadata.x==y");
|
||||
printFrom(JpaTarget.class, TargetFields.class, "metadata.x==y");
|
||||
printFrom(JpaTarget.class, TargetFields.class, "tag!=TAG1 and tag==TAG2");
|
||||
printFrom(JpaTarget.class, TargetFields.class, "tag==TAG1 and tag!=TAG2");
|
||||
|
||||
@@ -74,7 +74,7 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCond
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValueCreate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
@@ -341,12 +341,12 @@ public class TestdataFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@link SoftwareModuleMetadata} to every module of given {@link DistributionSet}.
|
||||
* Adds software module metadata to every module of given {@link DistributionSet}.
|
||||
* <p/>
|
||||
* {@link #VISIBLE_SM_MD_VALUE}, {@link #VISIBLE_SM_MD_KEY} with
|
||||
* {@link SoftwareModuleMetadata#isTargetVisible()} and
|
||||
* {@link MetadataValueCreate#isTargetVisible()} and
|
||||
* {@link #INVISIBLE_SM_MD_KEY}, {@link #INVISIBLE_SM_MD_VALUE} without
|
||||
* {@link SoftwareModuleMetadata#isTargetVisible()}
|
||||
* {@link MetadataValueCreate#isTargetVisible()}
|
||||
*
|
||||
* @param set to add metadata to
|
||||
*/
|
||||
@@ -1256,10 +1256,14 @@ public class TestdataFactory {
|
||||
}
|
||||
|
||||
private void addTestModuleMetadata(final SoftwareModule module) {
|
||||
softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(module.getId())
|
||||
.key(VISIBLE_SM_MD_KEY).value(VISIBLE_SM_MD_VALUE).targetVisible(true));
|
||||
softwareModuleManagement.updateMetadata(entityFactory.softwareModuleMetadata().create(module.getId())
|
||||
.key(INVISIBLE_SM_MD_KEY).value(INVISIBLE_SM_MD_VALUE).targetVisible(false));
|
||||
softwareModuleManagement.createMetadata(
|
||||
module.getId(),
|
||||
VISIBLE_SM_MD_KEY,
|
||||
new MetadataValueCreate(VISIBLE_SM_MD_VALUE, true));
|
||||
softwareModuleManagement.createMetadata(
|
||||
module.getId(),
|
||||
INVISIBLE_SM_MD_KEY,
|
||||
new MetadataValueCreate(INVISIBLE_SM_MD_VALUE, false));
|
||||
}
|
||||
|
||||
private void assertTargetProperlyCreated(final Target target) {
|
||||
|
||||
Reference in New Issue
Block a user