Software module metadata available to targets (in DMF and DDI) (#608)

* Software module metadata can be configure as target visible.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Added metadata to DDI.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Managed by UI.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Complete DMF integration and started UI.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Add DMF tests and completed UI.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Add RSQL test. Fix sonar issues.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Add JavaDocs. foreachtenant robustness.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Review feedback included.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Updated DMF docs.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* targetVisible optional in builder.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix typos.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix checkbox ID.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* DB optimization.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix component ID of sm metadat details tab.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
Kai Zimmermann
2017-12-16 17:17:54 +01:00
committed by GitHub
parent c3035231e2
commit 80d9f1b8fc
108 changed files with 1883 additions and 917 deletions

View File

@@ -27,6 +27,10 @@ We offer a sandbox installation that is free for everyone to try out hawkBit. Ho
https://hawkbit.eu-gb.mybluemix.net/UI/
In addition the following vendors offer free trial accounts for their hawkBit compatible products:
- [Bosch IoT Rollouts](https://www.bosch-iot-suite.com/rollouts/)
# Device Integration
hawkBit does not provide off the shelf clients for devices as part of the project. The long term goal is to provide an [Eclipse hono](https://github.com/eclipse/hono) integration which will provide connectivity through various IoT protocols and as a result allows a wide range of clients to connect to hawkBit. However, the hawkBit [Direct Device Integration (API) API](http://www.eclipse.org/hawkbit/documentation/interfaces/ddi-api.html) is HTTP/JSon based which should allow any update client to integrate quite easily.
@@ -83,7 +87,7 @@ $ java -jar ./hawkbit-device-simulator/target/hawkbit-device-simulator-#version#
## Generate getting started data with the [Management API example](https://github.com/eclipse/hawkbit-examples/tree/master/hawkbit-example-mgmt-simulator) (optional)
```
$ java -jar ./hawkbit-example-mgmt-simulator/target/hawkbit-example-mgmt-simulator-#version#.jar
$ java -jar ./hawkbit-example-mgmt-simulator/target/hawkbit-example-mgmt-simulator-#version#-exec.jar
```
# Releases and Roadmap

View File

@@ -237,7 +237,13 @@ Payload Template
"sha1":"String"
},
"size":long
}]
}],
"metadata":[
{
"key":"String",
"value":"String"
}
]
}]
}
```
@@ -249,7 +255,6 @@ Payload Template
| type=EVENT <br /> tenant=tenant123 <br /> thingId=abc <br /> topic=DOWNLOAD\_AND\_INSTALL | content_type=application/json
```json
{
"actionId":137,
"targetSecurityToken":"bH7XXAprK1ChnLfKSdtlsp7NOlPnZAYY",
"softwareModules":[
@@ -269,7 +274,13 @@ Payload Template
"sha1":"sha1hash"
},
"size":512
}]
}],
"metadata":[
{
"key":"installationType",
"value":"5784K#"
}
]
}]
}
```

View File

@@ -24,7 +24,12 @@ public enum SoftwareModuleMetadataFields implements FieldNameProvider {
/**
* The key field.
*/
KEY("key");
KEY("key"),
/**
* The target visible field.
*/
TARGETVISIBLE("targetVisible");
private final String fieldName;

View File

@@ -13,22 +13,33 @@ import java.util.List;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Deployment chunks.
*/
public class DdiChunk {
@JsonProperty("part")
@NotNull
private String part;
@JsonProperty("version")
@NotNull
private String version;
@JsonProperty("name")
@NotNull
private String name;
@JsonProperty("artifacts")
private List<DdiArtifact> artifacts;
@JsonProperty("metadata")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<DdiMetadata> metadata;
public DdiChunk() {
// needed for json create
}
@@ -44,13 +55,16 @@ public class DdiChunk {
* of the artifact
* @param artifacts
* download information
* @param metadata
* optional as additional information for the target/device
*/
public DdiChunk(final String part, final String version, final String name, final List<DdiArtifact> artifacts) {
super();
public DdiChunk(final String part, final String version, final String name, final List<DdiArtifact> artifacts,
final List<DdiMetadata> metadata) {
this.part = part;
this.version = version;
this.name = name;
this.artifacts = artifacts;
this.metadata = metadata;
}
public String getPart() {
@@ -73,4 +87,8 @@ public class DdiChunk {
return Collections.unmodifiableList(artifacts);
}
public List<DdiMetadata> getMetadata() {
return metadata;
}
}

View File

@@ -11,6 +11,9 @@ package org.eclipse.hawkbit.ddi.json.model;
import java.util.Collections;
import java.util.List;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
/**
@@ -22,6 +25,8 @@ public class DdiDeployment {
private HandlingType update;
@JsonProperty("chunks")
@NotNull
private List<DdiChunk> chunks;
/**
@@ -59,7 +64,7 @@ public class DdiDeployment {
if (chunks == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(chunks);
}

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ddi.json.model;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Additional metadata to be provided for the target/device.
*
*/
public class DdiMetadata {
@JsonProperty
@NotNull
private final String key;
@JsonProperty
@NotNull
private final String value;
public DdiMetadata(final String key, final String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
}

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.ddi.rest.resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.api.ApiType;
@@ -20,17 +21,22 @@ import org.eclipse.hawkbit.ddi.json.model.DdiArtifactHash;
import org.eclipse.hawkbit.ddi.json.model.DdiChunk;
import org.eclipse.hawkbit.ddi.json.model.DdiConfig;
import org.eclipse.hawkbit.ddi.json.model.DdiControllerBase;
import org.eclipse.hawkbit.ddi.json.model.DdiMetadata;
import org.eclipse.hawkbit.ddi.json.model.DdiPolling;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.ControllerManagement;
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.rest.data.ResponseList;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.mvc.ControllerLinkBuilder;
import org.springframework.http.HttpRequest;
import org.springframework.util.CollectionUtils;
/**
* Utility class for the DDI API.
@@ -43,15 +49,26 @@ public final class DataConversionHelper {
static List<DdiChunk> createChunks(final Target target, final Action uAction,
final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement,
final HttpRequest request) {
final HttpRequest request, final ControllerManagement controllerManagement) {
final Map<Long, List<SoftwareModuleMetadata>> metadata = controllerManagement
.findTargetVisibleMetaDataBySoftwareModuleId(uAction.getDistributionSet().getModules().stream()
.map(SoftwareModule::getId).collect(Collectors.toList()));
return uAction.getDistributionSet().getModules().stream()
.map(module -> new DdiChunk(mapChunkLegacyKeys(module.getType().getKey()), module.getVersion(),
module.getName(),
createArtifacts(target, module, artifactUrlHandler, systemManagement, request)))
createArtifacts(target, module, artifactUrlHandler, systemManagement, request),
mapMetadata(metadata.get(module.getId()))))
.collect(Collectors.toList());
}
private static List<DdiMetadata> mapMetadata(final List<SoftwareModuleMetadata> metadata) {
return CollectionUtils.isEmpty(metadata) ? null
: metadata.stream().map(md -> new DdiMetadata(md.getKey(), md.getValue())).collect(Collectors.toList());
}
private static String mapChunkLegacyKeys(final String key) {
if ("application".equals(key)) {
return "bApp";

View File

@@ -20,6 +20,7 @@ import org.eclipse.hawkbit.api.ArtifactUrlHandler;
import org.eclipse.hawkbit.artifact.repository.model.AbstractDbArtifact;
import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback;
import org.eclipse.hawkbit.ddi.json.model.DdiActionHistory;
import org.eclipse.hawkbit.ddi.json.model.DdiArtifact;
import org.eclipse.hawkbit.ddi.json.model.DdiCancel;
import org.eclipse.hawkbit.ddi.json.model.DdiCancelActionToStop;
import org.eclipse.hawkbit.ddi.json.model.DdiChunk;
@@ -115,8 +116,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
private EntityFactory entityFactory;
@Override
public ResponseEntity<List<org.eclipse.hawkbit.ddi.json.model.DdiArtifact>> getSoftwareModulesArtifacts(
@PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId,
public ResponseEntity<List<DdiArtifact>> getSoftwareModulesArtifacts(@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") final String controllerId,
@PathVariable("softwareModuleId") final Long softwareModuleId) {
LOG.debug("getSoftwareModulesArtifacts({})", controllerId);
@@ -270,7 +271,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
final List<DdiChunk> chunks = DataConversionHelper.createChunks(target, action, artifactUrlHandler,
systemManagement,
new ServletServerHttpRequest(requestResponseContextHolder.getHttpServletRequest()));
new ServletServerHttpRequest(requestResponseContextHolder.getHttpServletRequest()),
controllerManagement);
final HandlingType handlingType = action.isForce() ? HandlingType.FORCED : HandlingType.ATTEMPT;

View File

@@ -111,10 +111,10 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true);
final byte random[] = RandomUtils.nextBytes(5 * 1024);
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), getOsModule(ds),
"test1", false);
final Artifact artifactSignature = artifactManagement.create(new ByteArrayInputStream(random),
getOsModule(ds), "test1.signature", false);
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), getOsModule(ds), "test1",
false);
final Artifact artifactSignature = artifactManagement.create(new ByteArrayInputStream(random), getOsModule(ds),
"test1.signature", false);
final Target savedTarget = testdataFactory.createTarget("4712");
@@ -265,12 +265,19 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// Prepare test data
final DistributionSet ds = testdataFactory.createDistributionSet("", true);
final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true);
final String visibleMetadataOsKey = "metaDataVisible";
final String visibleMetadataOsValue = "withValue";
final byte random[] = RandomUtils.nextBytes(5 * 1024);
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), getOsModule(ds),
"test1", false);
final Artifact artifactSignature = artifactManagement.create(new ByteArrayInputStream(random),
getOsModule(ds), "test1.signature", false);
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), getOsModule(ds), "test1",
false);
final Artifact artifactSignature = artifactManagement.create(new ByteArrayInputStream(random), getOsModule(ds),
"test1.signature", false);
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(getOsModule(ds))
.key(visibleMetadataOsKey).value(visibleMetadataOsValue).targetVisible(true));
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(getOsModule(ds))
.key("metaDataNotVisible").value("withValue").targetVisible(false));
final Target savedTarget = testdataFactory.createTarget("4712");
@@ -328,6 +335,9 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
contains(ds.findFirstModuleByType(osType).get().getName())))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].version",
contains(ds.findFirstModuleByType(osType).get().getVersion())))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].metadata[0].key").value(visibleMetadataOsKey))
.andExpect(
jsonPath("$.deployment.chunks[?(@.part==os)].metadata[0].value").value(visibleMetadataOsValue))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0].size", contains(5 * 1024)))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0].filename", contains("test1")))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0].hashes.md5",
@@ -362,8 +372,9 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
+ "/artifacts/test1.signature.MD5SUM")))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==bApp)].version",
contains(ds.findFirstModuleByType(appType).get().getVersion())))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==bApp)].name",
contains(ds.findFirstModuleByType(appType).get().getName())));
.andExpect(jsonPath("$.deployment.chunks[?(@.part==bApp)].metadata").doesNotExist())
.andExpect(jsonPath("$.deployment.chunks[?(@.part==bApp)].name")
.value(ds.findFirstModuleByType(appType).get().getName()));
// Retrieved is reported
final List<ActionStatus> actionStatusMessages = deploymentManagement
@@ -381,10 +392,10 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true);
final byte random[] = RandomUtils.nextBytes(5 * 1024);
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), getOsModule(ds),
"test1", false);
final Artifact artifactSignature = artifactManagement.create(new ByteArrayInputStream(random),
getOsModule(ds), "test1.signature", false);
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), getOsModule(ds), "test1",
false);
final Artifact artifactSignature = artifactManagement.create(new ByteArrayInputStream(random), getOsModule(ds),
"test1.signature", false);
final Target savedTarget = testdataFactory.createTarget("4712");

View File

@@ -19,6 +19,7 @@ import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
@@ -311,9 +312,11 @@ public class AmqpConfiguration {
AmqpMessageDispatcherService amqpMessageDispatcherService(final RabbitTemplate rabbitTemplate,
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement) {
final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement,
final SoftwareModuleManagement softwareModuleManagement) {
return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler,
systemSecurityContext, systemManagement, targetManagement, serviceMatcher, distributionSetManagement);
systemSecurityContext, systemManagement, targetManagement, serviceMatcher, distributionSetManagement,
softwareModuleManagement);
}
private static Map<String, Object> getTTLMaxArgsAuthenticationQueue() {

View File

@@ -9,9 +9,10 @@
package org.eclipse.hawkbit.amqp;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.api.ApiType;
@@ -25,8 +26,11 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.DmfArtifact;
import org.eclipse.hawkbit.dmf.json.model.DmfArtifactHash;
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
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.event.remote.TargetAssignDistributionSetEvent;
@@ -34,6 +38,7 @@ import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
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.security.SystemSecurityContext;
import org.eclipse.hawkbit.util.IpUtil;
@@ -46,6 +51,9 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.cloud.bus.ServiceMatcher;
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.data.domain.PageRequest;
import com.google.common.collect.Maps;
/**
* {@link AmqpMessageDispatcherService} create all outgoing AMQP messages and
@@ -66,6 +74,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
private final TargetManagement targetManagement;
private final ServiceMatcher serviceMatcher;
private final DistributionSetManagement distributionSetManagement;
private final SoftwareModuleManagement softwareModuleManagement;
/**
* Constructor.
@@ -92,7 +101,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
final TargetManagement targetManagement, final ServiceMatcher serviceMatcher,
final DistributionSetManagement distributionSetManagement) {
final DistributionSetManagement distributionSetManagement,
final SoftwareModuleManagement softwareModuleManagement) {
super(rabbitTemplate);
this.artifactUrlHandler = artifactUrlHandler;
this.amqpSenderService = amqpSenderService;
@@ -101,6 +111,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
this.targetManagement = targetManagement;
this.serviceMatcher = serviceMatcher;
this.distributionSetManagement = distributionSetManagement;
this.softwareModuleManagement = softwareModuleManagement;
}
/**
@@ -118,11 +129,22 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
LOG.debug("targetAssignDistributionSet retrieved. I will forward it to DMF broker.");
distributionSetManagement.get(assignedEvent.getDistributionSetId()).ifPresent(set ->
distributionSetManagement.get(assignedEvent.getDistributionSetId()).ifPresent(set -> {
targetManagement.getByControllerID(assignedEvent.getActions().keySet())
.forEach(target -> sendUpdateMessageToTarget(assignedEvent.getTenant(), target,
assignedEvent.getActions().get(target.getControllerId()), set.getModules())));
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules = Maps
.newHashMapWithExpectedSize(set.getModules().size());
set.getModules()
.forEach(
module -> modules.put(module,
softwareModuleManagement.findMetaDataBySoftwareModuleIdAndTargetVisible(
new PageRequest(0, RepositoryConstants.MAX_META_DATA_COUNT), module.getId())
.getContent()));
targetManagement.getByControllerID(assignedEvent.getActions().keySet())
.forEach(target -> sendUpdateMessageToTarget(assignedEvent.getTenant(), target,
assignedEvent.getActions().get(target.getControllerId()), modules));
});
}
/**
@@ -159,7 +181,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
protected void sendUpdateMessageToTarget(final String tenant, final Target target, final Long actionId,
final Collection<SoftwareModule> modules) {
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules) {
final URI targetAdress = target.getAddress();
if (!IpUtil.isAmqpUri(targetAdress)) {
@@ -172,10 +194,11 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
final String targetSecurityToken = systemSecurityContext.runAsSystem(target::getSecurityToken);
downloadAndUpdateRequest.setTargetSecurityToken(targetSecurityToken);
for (final SoftwareModule softwareModule : modules) {
final DmfSoftwareModule amqpSoftwareModule = convertToAmqpSoftwareModule(target, softwareModule);
modules.entrySet().forEach(entry -> {
final DmfSoftwareModule amqpSoftwareModule = convertToAmqpSoftwareModule(target, entry);
downloadAndUpdateRequest.addSoftwareModule(amqpSoftwareModule);
}
});
final Message message = getMessageConverter().toMessage(downloadAndUpdateRequest,
createConnectorMessagePropertiesEvent(tenant, target.getControllerId(),
@@ -248,17 +271,22 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
return messageProperties;
}
private DmfSoftwareModule convertToAmqpSoftwareModule(final Target target, final SoftwareModule softwareModule) {
private DmfSoftwareModule convertToAmqpSoftwareModule(final Target target,
final Entry<SoftwareModule, List<SoftwareModuleMetadata>> entry) {
final DmfSoftwareModule amqpSoftwareModule = new DmfSoftwareModule();
amqpSoftwareModule.setModuleId(softwareModule.getId());
amqpSoftwareModule.setModuleType(softwareModule.getType().getKey());
amqpSoftwareModule.setModuleVersion(softwareModule.getVersion());
amqpSoftwareModule.setModuleId(entry.getKey().getId());
amqpSoftwareModule.setModuleType(entry.getKey().getType().getKey());
amqpSoftwareModule.setModuleVersion(entry.getKey().getVersion());
amqpSoftwareModule.setArtifacts(convertArtifacts(target, entry.getKey().getArtifacts()));
amqpSoftwareModule.setMetadata(convertMetadata(entry.getValue()));
final List<DmfArtifact> artifacts = convertArtifacts(target, softwareModule.getArtifacts());
amqpSoftwareModule.setArtifacts(artifacts);
return amqpSoftwareModule;
}
private List<DmfMetadata> convertMetadata(final List<SoftwareModuleMetadata> metadata) {
return metadata.stream().map(md -> new DmfMetadata(md.getKey(), md.getValue())).collect(Collectors.toList());
}
private List<DmfArtifact> convertArtifacts(final Target target, final List<Artifact> localArtifacts) {
if (localArtifacts.isEmpty()) {
return Collections.emptyList();

View File

@@ -12,8 +12,10 @@ import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
@@ -28,6 +30,8 @@ import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
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.util.IpUtil;
import org.slf4j.Logger;
@@ -45,6 +49,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.util.StringUtils;
import com.google.common.collect.Maps;
/**
*
* {@link AmqpMessageHandlerService} handles all incoming target interaction
@@ -199,8 +205,17 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
return;
}
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules = Maps
.newHashMapWithExpectedSize(action.getDistributionSet().getModules().size());
final Map<Long, List<SoftwareModuleMetadata>> metadata = controllerManagement
.findTargetVisibleMetaDataBySoftwareModuleId(action.getDistributionSet().getModules().stream()
.map(SoftwareModule::getId).collect(Collectors.toList()));
action.getDistributionSet().getModules().forEach(module -> modules.put(module, metadata.get(module.getId())));
amqpMessageDispatcherService.sendUpdateMessageToTarget(action.getTenant(), action.getTarget(), action.getId(),
action.getDistributionSet().getModules());
modules);
}
/**

View File

@@ -34,6 +34,7 @@ import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
@@ -46,6 +47,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TenantMetaData;
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.eclipse.hawkbit.util.IpUtil;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -109,7 +111,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
amqpMessageDispatcherService = new AmqpMessageDispatcherService(rabbitTemplate, senderService,
artifactUrlHandlerMock, systemSecurityContext, systemManagement, targetManagement, serviceMatcher,
distributionSetManagement);
distributionSetManagement, softwareModuleManagement);
}
@@ -129,6 +131,8 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
public void testSendDownloadRequesWithSoftwareModulesAndNoArtifacts() {
final DistributionSet createDistributionSet = testdataFactory
.createDistributionSet(UUID.randomUUID().toString());
testdataFactory.addSoftwareModuleMetadata(createDistributionSet);
final Action action = createAction(createDistributionSet);
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
@@ -142,6 +146,10 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
for (final org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule softwareModule : downloadAndUpdateRequest
.getSoftwareModules()) {
assertTrue("Artifact list for softwaremodule should be empty", softwareModule.getArtifacts().isEmpty());
assertThat(softwareModule.getMetadata()).containsExactly(
new DmfMetadata(TestdataFactory.VISIBLE_SM_MD_KEY, TestdataFactory.VISIBLE_SM_MD_VALUE));
for (final SoftwareModule softwareModule2 : action.getDistributionSet().getModules()) {
assertNotNull("Sofware module ID should be set", softwareModule.getModuleId());
if (!softwareModule.getModuleId().equals(softwareModule2.getId())) {

View File

@@ -22,7 +22,6 @@ import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
@@ -421,7 +420,7 @@ public class AmqpMessageHandlerServiceTest {
final ArgumentCaptor<Long> actionIdCaptor = ArgumentCaptor.forClass(Long.class);
verify(amqpMessageDispatcherServiceMock, times(1)).sendUpdateMessageToTarget(tenantCaptor.capture(),
targetCaptor.capture(), actionIdCaptor.capture(), any(Collection.class));
targetCaptor.capture(), actionIdCaptor.capture(), any(Map.class));
final String tenant = tenantCaptor.getValue();
final String controllerId = targetCaptor.getValue().getControllerId();
final Long actionId = actionIdCaptor.getValue();

View File

@@ -20,6 +20,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -45,6 +46,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AmqpServiceInte
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 2) })
public void sendDownloadAndInstallStatus() {
@@ -63,6 +65,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AmqpServiceInte
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetPollEvent.class, count = 3) })
public void assignDistributionSetMultipleTimes() {
@@ -88,6 +91,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AmqpServiceInte
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 2) })
public void sendCancelStatus() {

View File

@@ -30,6 +30,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.model.Action.Status;
@@ -363,6 +364,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetPollEvent.class, count = 1) })
public void finishActionStatus() {
@@ -376,6 +378,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 0), @Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void runningActionStatus() {
@@ -389,6 +392,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void downloadActionStatus() {
@@ -402,6 +406,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetPollEvent.class, count = 1) })
public void errorActionStatus() {
@@ -415,6 +420,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void warningActionStatus() {
@@ -428,6 +434,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void retrievedActionStatus() {
@@ -441,6 +448,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void cancelNotAllowActionStatus() {
@@ -455,6 +463,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 2) })
public void receiveDownLoadAndInstallMessageAfterAssignment() {
@@ -463,6 +472,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
// setup
createAndSendTarget(controllerId, TENANT_EXIST);
final DistributionSet distributionSet = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
testdataFactory.addSoftwareModuleMetadata(distributionSet);
assignDistributionSet(distributionSet.getId(), controllerId);
// test
@@ -507,6 +517,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
@@ -526,6 +537,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void canceledRejectedNotAllowActionStatus() {
@@ -541,6 +553,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void canceledRejectedActionStatus() {

View File

@@ -24,6 +24,7 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.DmfAttributeUpdate;
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
import org.eclipse.hawkbit.integration.listener.DeadletterListener;
import org.eclipse.hawkbit.integration.listener.ReplyToListener;
import org.eclipse.hawkbit.matcher.SoftwareModuleJsonMatcher;
@@ -35,6 +36,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.eclipse.hawkbit.util.IpUtil;
import org.junit.Assert;
import org.junit.Before;
@@ -107,6 +109,8 @@ public abstract class AmqpServiceIntegrationTest extends AbstractAmqpIntegration
protected DistributionSetAssignmentResult registerTargetAndAssignDistributionSet(final String controllerId) {
distributionSet = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
testdataFactory.addSoftwareModuleMetadata(distributionSet);
return registerTargetAndAssignDistributionSet(distributionSet.getId(), TargetUpdateStatus.REGISTERED,
distributionSet.getModules(), controllerId);
}
@@ -165,6 +169,10 @@ public abstract class AmqpServiceIntegrationTest extends AbstractAmqpIntegration
Assert.assertThat(dsModules,
SoftwareModuleJsonMatcher.containsExactly(downloadAndUpdateRequest.getSoftwareModules()));
downloadAndUpdateRequest.getSoftwareModules()
.forEach(dmfModule -> assertThat(dmfModule.getMetadata()).containsExactly(
new DmfMetadata(TestdataFactory.VISIBLE_SM_MD_KEY, TestdataFactory.VISIBLE_SM_MD_VALUE)));
final Target updatedTarget = waitUntilIsPresent(() -> targetManagement.getByControllerID(controllerId));
assertThat(updatedTarget.getSecurityToken()).isEqualTo(downloadAndUpdateRequest.getTargetSecurityToken());

View File

@@ -12,6 +12,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
@@ -44,21 +45,19 @@ public final class SoftwareModuleJsonMatcher {
* the json sofware modules.
*/
@Factory
public static SoftwareModulesMatcher containsExactly(
final List<org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule> expectedModules) {
public static SoftwareModulesMatcher containsExactly(final List<DmfSoftwareModule> expectedModules) {
return new SoftwareModulesMatcher(expectedModules);
}
private static class SoftwareModulesMatcher extends BaseMatcher<Set<SoftwareModule>> {
private final List<org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule> expectedModules;
private final List<DmfSoftwareModule> expectedModules;
public SoftwareModulesMatcher(List<org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule> expectedModules) {
public SoftwareModulesMatcher(final List<DmfSoftwareModule> expectedModules) {
this.expectedModules = expectedModules;
}
static boolean containsExactly(Object actual,
List<org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule> expected) {
static boolean containsExactly(final Object actual, final List<DmfSoftwareModule> expected) {
if (actual == null) {
return expected == null;
}
@@ -73,7 +72,7 @@ public final class SoftwareModuleJsonMatcher {
for (final SoftwareModule repoSoftwareModule : modules) {
boolean containsElement = false;
for (final org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule jsonSoftwareModule : expected) {
for (final DmfSoftwareModule jsonSoftwareModule : expected) {
if (!jsonSoftwareModule.getModuleId().equals(repoSoftwareModule.getId())) {
continue;
}
@@ -100,12 +99,12 @@ public final class SoftwareModuleJsonMatcher {
}
@Override
public boolean matches(Object actualValue) {
public boolean matches(final Object actualValue) {
return containsExactly(actualValue, expectedModules);
}
@Override
public void describeTo(Description description) {
public void describeTo(final Description description) {
description.appendValue(expectedModules);
}
}

View File

@@ -32,7 +32,6 @@ public class DmfArtifactHash {
*/
@JsonCreator
public DmfArtifactHash(@JsonProperty("sha1") final String sha1, @JsonProperty("md5") final String md5) {
super();
this.sha1 = sha1;
this.md5 = md5;
}

View File

@@ -0,0 +1,82 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.dmf.json.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Additional metadata to be provided for the target/device.
*
*/
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class DmfMetadata {
@JsonProperty
private final String key;
@JsonProperty
private final String value;
@JsonCreator
public DmfMetadata(@JsonProperty("key") final String key, @JsonProperty("value") final String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DmfMetadata other = (DmfMetadata) obj;
if (key == null) {
if (other.key != null) {
return false;
}
} else if (!key.equals(other.key)) {
return false;
}
if (value == null) {
if (other.value != null) {
return false;
}
} else if (!value.equals(other.value)) {
return false;
}
return true;
}
}

View File

@@ -20,9 +20,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/**
* JSON representation of a software module.
*
*
*
*
*/
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@@ -36,6 +33,8 @@ public class DmfSoftwareModule {
private String moduleVersion;
@JsonProperty
private List<DmfArtifact> artifacts;
@JsonProperty
private List<DmfMetadata> metadata;
public String getModuleType() {
return moduleType;
@@ -74,4 +73,14 @@ public class DmfSoftwareModule {
this.artifacts = artifacts;
}
public List<DmfMetadata> getMetadata() {
return metadata;
}
public void setMetadata(final List<DmfMetadata> metadata) {
if (metadata != null && !metadata.isEmpty()) {
this.metadata = metadata;
}
}
}

View File

@@ -14,7 +14,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* The representation of an meta data in the REST API.
* The representation of an meta data in the REST API for POST/Create.
*
*/
@JsonInclude(Include.NON_NULL)
@@ -26,32 +26,18 @@ public class MgmtMetadata {
@JsonProperty
private String value;
/**
* @return the key
*/
public String getKey() {
return key;
}
/**
* @param key
* the key to set
*/
public void setKey(final String key) {
this.key = key;
}
/**
* @return the value
*/
public String getValue() {
return value;
}
/**
* @param value
* the value to set
*/
public void setValue(final String value) {
this.value = value;
}

View File

@@ -0,0 +1,34 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.json.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* The representation of an meta data in the REST API for PUT/Update.
*
*/
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class MgmtMetadataBodyPut {
@JsonProperty
private String value;
public String getValue() {
return value;
}
public void setValue(final String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.json.model.softwaremodule;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* The representation of SoftwareModuleMetadata in the REST API for POST/Create.
*
*/
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class MgmtSoftwareModuleMetadata {
@JsonProperty(required = true)
private String key;
@JsonProperty
private String value;
@JsonProperty
private boolean targetVisible;
public String getKey() {
return key;
}
public void setKey(final String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(final String value) {
this.value = value;
}
public boolean isTargetVisible() {
return targetVisible;
}
public void setTargetVisible(final boolean targetVisible) {
this.targetVisible = targetVisible;
}
}

View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.json.model.softwaremodule;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* The representation of an meta data in the REST API for PUT/Update.
*
*/
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class MgmtSoftwareModuleMetadataBodyPut {
@JsonProperty
private String value;
@JsonProperty
private Boolean targetVisible;
public String getValue() {
return value;
}
public void setValue(final String value) {
this.value = value;
}
public Boolean isTargetVisible() {
return targetVisible;
}
public void setTargetVisible(final Boolean targetVisible) {
this.targetVisible = targetVisible;
}
}

View File

@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.mgmt.rest.api;
import java.util.List;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost;
@@ -256,7 +257,8 @@ public interface MgmtDistributionSetRestApi {
*/
@RequestMapping(method = RequestMethod.GET, value = "/{distributionSetId}/metadata", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<PagedList<MgmtMetadata>> getMetadata(@PathVariable("distributionSetId") Long distributionSetId,
ResponseEntity<PagedList<MgmtMetadata>> getMetadata(
@PathVariable("distributionSetId") Long distributionSetId,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) int pagingOffsetParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) int pagingLimitParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) String sortParam,
@@ -292,7 +294,7 @@ public interface MgmtDistributionSetRestApi {
@RequestMapping(method = RequestMethod.PUT, value = "/{distributionSetId}/metadata/{metadataKey}", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtMetadata> updateMetadata(@PathVariable("distributionSetId") Long distributionSetId,
@PathVariable("metadataKey") String metadataKey, MgmtMetadata metadata);
@PathVariable("metadataKey") String metadataKey, MgmtMetadataBodyPut metadata);
/**
* Deletes a single meta data entry from the distribution set.

View File

@@ -185,6 +185,9 @@ public final class MgmtRestConstants {
*/
public static final String SOFTWAREMODULETYPE_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/softwaremoduletypes";
/**
* The distributon set base resource.
*/
public static final String DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING
+ "/distributionsettypes";

View File

@@ -10,10 +10,11 @@ package org.eclipse.hawkbit.mgmt.rest.api;
import java.util.List;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleMetadata;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleMetadataBodyPut;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPut;
import org.springframework.hateoas.MediaTypes;
@@ -214,7 +215,8 @@ public interface MgmtSoftwareModuleRestApi {
*/
@RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/metadata", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<PagedList<MgmtMetadata>> getMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId,
ResponseEntity<PagedList<MgmtSoftwareModuleMetadata>> getMetadata(
@PathVariable("softwareModuleId") final Long softwareModuleId,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
@@ -232,7 +234,8 @@ public interface MgmtSoftwareModuleRestApi {
*/
@RequestMapping(method = RequestMethod.GET, value = "/{softwareModuleId}/metadata/{metadataKey}", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtMetadata> getMetadataValue(@PathVariable("softwareModuleId") final Long softwareModuleId,
ResponseEntity<MgmtSoftwareModuleMetadata> getMetadataValue(
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("metadataKey") final String metadataKey);
/**
@@ -242,13 +245,16 @@ public interface MgmtSoftwareModuleRestApi {
* the ID of the software module to update the meta data entry
* @param metadataKey
* the key of the meta data to update the value
* @param metadata
* body to update
* @return status OK if the update request is successful and the updated
* meta data result
*/
@RequestMapping(method = RequestMethod.PUT, value = "/{softwareModuleId}/metadata/{metadataKey}", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtMetadata> updateMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("metadataKey") final String metadataKey, final MgmtMetadata metadata);
ResponseEntity<MgmtSoftwareModuleMetadata> updateMetadata(
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("metadataKey") final String metadataKey, final MgmtSoftwareModuleMetadataBodyPut metadata);
/**
* Deletes a single meta data entry from the software module.
@@ -276,7 +282,8 @@ public interface MgmtSoftwareModuleRestApi {
@RequestMapping(method = RequestMethod.POST, value = "/{softwareModuleId}/metadata", consumes = {
MediaType.APPLICATION_JSON_VALUE,
MediaTypes.HAL_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<List<MgmtMetadata>> createMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId,
final List<MgmtMetadata> metadataRest);
ResponseEntity<List<MgmtSoftwareModuleMetadata>> createMetadata(
@PathVariable("softwareModuleId") final Long softwareModuleId,
final List<MgmtSoftwareModuleMetadata> metadataRest);
}

View File

@@ -13,6 +13,7 @@ import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost;
@@ -298,8 +299,9 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
}
@Override
public ResponseEntity<MgmtMetadata> updateMetadata(@PathVariable("distributionSetId") final Long distributionSetId,
@PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadata metadata) {
public ResponseEntity<MgmtMetadata> updateMetadata(
@PathVariable("distributionSetId") final Long distributionSetId,
@PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadataBodyPut metadata) {
// check if distribution set exists otherwise throw exception
// immediately
final DistributionSetMetadata updated = distributionSetManagement.updateMetaData(distributionSetId,

View File

@@ -16,18 +16,18 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifactHash;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleMetadata;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.rest.data.ResponseList;
@@ -48,14 +48,16 @@ public final class MgmtSoftwareModuleMapper {
.version(smsRest.getVersion()).description(smsRest.getDescription()).vendor(smsRest.getVendor());
}
static List<MetaData> fromRequestSwMetadata(final EntityFactory entityFactory,
final Collection<MgmtMetadata> metadata) {
static List<SoftwareModuleMetadataCreate> fromRequestSwMetadata(final EntityFactory entityFactory,
final Long softwareModuleId, final Collection<MgmtSoftwareModuleMetadata> metadata) {
if (metadata == null) {
return Collections.emptyList();
}
return metadata.stream()
.map(metadataRest -> entityFactory.generateMetadata(metadataRest.getKey(), metadataRest.getValue()))
.map(metadataRest -> entityFactory.softwareModuleMetadata().create(softwareModuleId)
.key(metadataRest.getKey()).value(metadataRest.getValue())
.targetVisible(metadataRest.isTargetVisible()))
.collect(Collectors.toList());
}
@@ -77,7 +79,8 @@ public final class MgmtSoftwareModuleMapper {
softwareModules.stream().map(MgmtSoftwareModuleMapper::toResponse).collect(Collectors.toList()));
}
static List<MgmtMetadata> toResponseSwMetadata(final Collection<SoftwareModuleMetadata> metadata) {
static List<MgmtSoftwareModuleMetadata> toResponseSwMetadata(
final Collection<SoftwareModuleMetadata> metadata) {
if (metadata == null) {
return Collections.emptyList();
}
@@ -85,10 +88,11 @@ public final class MgmtSoftwareModuleMapper {
return metadata.stream().map(MgmtSoftwareModuleMapper::toResponseSwMetadata).collect(Collectors.toList());
}
static MgmtMetadata toResponseSwMetadata(final SoftwareModuleMetadata metadata) {
final MgmtMetadata metadataRest = new MgmtMetadata();
static MgmtSoftwareModuleMetadata toResponseSwMetadata(final SoftwareModuleMetadata metadata) {
final MgmtSoftwareModuleMetadata metadataRest = new MgmtSoftwareModuleMetadata();
metadataRest.setKey(metadata.getKey());
metadataRest.setValue(metadata.getValue());
metadataRest.setTargetVisible(metadata.isTargetVisible());
return metadataRest;
}

View File

@@ -12,10 +12,11 @@ import java.io.IOException;
import java.util.Collection;
import java.util.List;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleMetadata;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleMetadataBodyPut;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPut;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
@@ -205,7 +206,7 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
}
@Override
public ResponseEntity<PagedList<MgmtMetadata>> getMetadata(
public ResponseEntity<PagedList<MgmtSoftwareModuleMetadata>> getMetadata(
@PathVariable("softwareModuleId") final Long softwareModuleId,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
@@ -234,7 +235,8 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
}
@Override
public ResponseEntity<MgmtMetadata> getMetadataValue(@PathVariable("softwareModuleId") final Long softwareModuleId,
public ResponseEntity<MgmtSoftwareModuleMetadata> getMetadataValue(
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("metadataKey") final String metadataKey) {
final SoftwareModuleMetadata findOne = softwareModuleManagement
@@ -245,10 +247,13 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
}
@Override
public ResponseEntity<MgmtMetadata> updateMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadata metadata) {
final SoftwareModuleMetadata updated = softwareModuleManagement.updateMetaData(softwareModuleId,
entityFactory.generateMetadata(metadataKey, metadata.getValue()));
public ResponseEntity<MgmtSoftwareModuleMetadata> updateMetadata(
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("metadataKey") final String metadataKey,
@RequestBody final MgmtSoftwareModuleMetadataBodyPut metadata) {
final SoftwareModuleMetadata updated = softwareModuleManagement
.updateMetaData(entityFactory.softwareModuleMetadata().update(softwareModuleId, metadataKey)
.value(metadata.getValue()).targetVisible(metadata.isTargetVisible()));
return ResponseEntity.ok(MgmtSoftwareModuleMapper.toResponseSwMetadata(updated));
}
@@ -262,12 +267,12 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
}
@Override
public ResponseEntity<List<MgmtMetadata>> createMetadata(
public ResponseEntity<List<MgmtSoftwareModuleMetadata>> createMetadata(
@PathVariable("softwareModuleId") final Long softwareModuleId,
@RequestBody final List<MgmtMetadata> metadataRest) {
@RequestBody final List<MgmtSoftwareModuleMetadata> metadataRest) {
final List<SoftwareModuleMetadata> created = softwareModuleManagement.createMetaData(softwareModuleId,
MgmtSoftwareModuleMapper.fromRequestSwMetadata(entityFactory, metadataRest));
final List<SoftwareModuleMetadata> created = softwareModuleManagement.createMetaData(
MgmtSoftwareModuleMapper.fromRequestSwMetadata(entityFactory, softwareModuleId, metadataRest));
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtSoftwareModuleMapper.toResponseSwMetadata(created));
}

View File

@@ -85,9 +85,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final String updateVendor = "newVendor1";
final String updateDescription = "newDescription1";
SoftwareModule sm = softwareModuleManagement
.create(entityFactory.softwareModule().create().type(osType).name(knownSWName)
.version(knownSWVersion).description(knownSWDescription).vendor(knownSWVendor));
SoftwareModule sm = softwareModuleManagement.create(entityFactory.softwareModule().create().type(osType)
.name(knownSWName).version(knownSWVersion).description(knownSWDescription).vendor(knownSWVendor));
assertThat(sm.getName()).as("Wrong name of the software module").isEqualTo(knownSWName);
@@ -140,8 +139,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
// check rest of response compared to DB
final MgmtArtifact artResult = ResourceUtility
.convertArtifactResponse(mvcResult.getResponse().getContentAsString());
final Long artId = softwareModuleManagement.get(sm.getId()).get().getArtifacts().get(0)
.getId();
final Long artId = softwareModuleManagement.get(sm.getId()).get().getArtifacts().get(0).getId();
assertThat(artResult.getArtifactId()).as("Wrong artifact id").isEqualTo(artId);
assertThat(JsonPath.compile("$._links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
.as("Link contains no self url")
@@ -159,8 +157,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
assertThat(artifactManagement.count()).as("Wrong artifact size").isEqualTo(1);
// binary
try (InputStream fileInputStream = artifactManagement.loadArtifactBinary(
softwareModuleManagement.get(sm.getId()).get().getArtifacts().get(0).getSha1Hash())
try (InputStream fileInputStream = artifactManagement
.loadArtifactBinary(softwareModuleManagement.get(sm.getId()).get().getArtifacts().get(0).getSha1Hash())
.get().getFileInputStream()) {
assertTrue("Wrong artifact content",
IOUtils.contentEquals(new ByteArrayInputStream(random), fileInputStream));
@@ -174,9 +172,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
.isEqualTo(HashGeneratorUtils.generateMD5(random));
// metadata
assertThat(
softwareModuleManagement.get(sm.getId()).get().getArtifacts().get(0).getFilename())
.as("wrong metadata of the filename").isEqualTo("origFilename");
assertThat(softwareModuleManagement.get(sm.getId()).get().getArtifacts().get(0).getFilename())
.as("wrong metadata of the filename").isEqualTo("origFilename");
}
@Test
@@ -237,8 +234,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
assertThat(artifactManagement.count()).isEqualTo(1);
// hashes
assertThat(artifactManagement.getByFilename("customFilename")).as("Local artifact is wrong")
.isPresent();
assertThat(artifactManagement.getByFilename("customFilename")).as("Local artifact is wrong").isPresent();
}
@Test
@@ -291,10 +287,10 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final byte random[] = RandomStringUtils.random(5 * 1024).getBytes();
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(),
"file1", false);
final Artifact artifact2 = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(),
"file2", false);
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1",
false);
final Artifact artifact2 = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file2",
false);
downloadAndVerify(sm, random, artifact);
downloadAndVerify(sm, random, artifact2);
@@ -321,8 +317,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
final byte random[] = RandomStringUtils.random(5 * 1024).getBytes();
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(),
"file1", false);
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1",
false);
// perform test
mvc.perform(get("/rest/v1/softwaremodules/{smId}/artifacts/{artId}", sm.getId(), artifact.getId())
@@ -347,10 +343,10 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final byte random[] = RandomStringUtils.random(5 * 1024).getBytes();
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(),
"file1", false);
final Artifact artifact2 = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(),
"file2", false);
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1",
false);
final Artifact artifact2 = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file2",
false);
mvc.perform(get("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -678,16 +674,14 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
.isEqualTo("http://localhost/rest/v1/softwaremodules/" + appCreated.getId());
assertThat(softwareModuleManagement.findAll(PAGE)).as("Wrong softwaremodule size").hasSize(2);
assertThat(
softwareModuleManagement.findByType(PAGE, osType.getId()).getContent().get(0).getName())
.as("Softwaremoudle name is wrong").isEqualTo(os.getName());
assertThat(softwareModuleManagement.findByType(PAGE, osType.getId()).getContent().get(0)
.getCreatedBy()).as("Softwaremoudle created by is wrong").isEqualTo("uploadTester");
assertThat(softwareModuleManagement.findByType(PAGE, osType.getId()).getContent().get(0)
.getCreatedAt()).as("Softwaremoudle created at is wrong").isGreaterThanOrEqualTo(current);
assertThat(
softwareModuleManagement.findByType(PAGE, appType.getId()).getContent().get(0).getName())
.as("Softwaremoudle name is wrong").isEqualTo(ah.getName());
assertThat(softwareModuleManagement.findByType(PAGE, osType.getId()).getContent().get(0).getName())
.as("Softwaremoudle name is wrong").isEqualTo(os.getName());
assertThat(softwareModuleManagement.findByType(PAGE, osType.getId()).getContent().get(0).getCreatedBy())
.as("Softwaremoudle created by is wrong").isEqualTo("uploadTester");
assertThat(softwareModuleManagement.findByType(PAGE, osType.getId()).getContent().get(0).getCreatedAt())
.as("Softwaremoudle created at is wrong").isGreaterThanOrEqualTo(current);
assertThat(softwareModuleManagement.findByType(PAGE, appType.getId()).getContent().get(0).getName())
.as("Softwaremoudle name is wrong").isEqualTo(ah.getName());
}
@Test
@@ -706,8 +700,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
mvc.perform(delete("/rest/v1/softwaremodules/{smId}", sm.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(softwareModuleManagement.findAll(PAGE))
.as("After delete no softwarmodule should be available").isEmpty();
assertThat(softwareModuleManagement.findAll(PAGE)).as("After delete no softwarmodule should be available")
.isEmpty();
assertThat(artifactManagement.count()).isEqualTo(0);
}
@@ -718,8 +712,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final byte random[] = RandomStringUtils.random(5 * 1024).getBytes();
artifactManagement.create(new ByteArrayInputStream(random),
ds1.findFirstModuleByType(appType).get().getId(), "file1", false);
artifactManagement.create(new ByteArrayInputStream(random), ds1.findFirstModuleByType(appType).get().getId(),
"file1", false);
assertThat(softwareModuleManagement.findAll(PAGE)).hasSize(3);
assertThat(artifactManagement.count()).isEqualTo(1);
@@ -746,8 +740,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final byte random[] = RandomStringUtils.random(5 * 1024).getBytes();
// Create 2 artifacts
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(),
"file1", false);
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1",
false);
artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file2", false);
// check repo before delete
@@ -761,8 +755,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
// check that only one artifact is still alive and still assigned
assertThat(softwareModuleManagement.findAll(PAGE)).as("After the sm should be marked as deleted")
.hasSize(1);
assertThat(softwareModuleManagement.findAll(PAGE)).as("After the sm should be marked as deleted").hasSize(1);
assertThat(artifactManagement.count()).isEqualTo(1);
assertThat(softwareModuleManagement.get(sm.getId()).get().getArtifacts())
.as("After delete artifact should available for marked as deleted sm's").hasSize(1);
@@ -775,22 +768,23 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final String knownKey1 = "knownKey1";
final String knownValue1 = "knownValue1";
final String knownKey2 = "knownKey1";
final String knownKey2 = "knownKey2";
final String knownValue2 = "knownValue1";
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
final JSONArray jsonArray = new JSONArray();
jsonArray.put(new JSONObject().put("key", knownKey1).put("value", knownValue1));
jsonArray.put(new JSONObject().put("key", knownKey2).put("value", knownValue2));
jsonArray.put(new JSONObject().put("key", knownKey2).put("value", knownValue2).put("targetVisible", true));
mvc.perform(post("/rest/v1/softwaremodules/{swId}/metadata", sm.getId()).accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).content(jsonArray.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0]key", equalTo(knownKey1))).andExpect(jsonPath("[0]value", equalTo(knownValue1)))
.andExpect(jsonPath("[1]key", equalTo(knownKey2)))
.andExpect(jsonPath("[1]value", equalTo(knownValue2)));
.andExpect(jsonPath("[0]targetVisible", equalTo(false)))
.andExpect(jsonPath("[1]key", equalTo(knownKey2))).andExpect(jsonPath("[1]value", equalTo(knownValue2)))
.andExpect(jsonPath("[1]targetVisible", equalTo(true)));
final SoftwareModuleMetadata metaKey1 = softwareModuleManagement
.getMetaDataBySoftwareModuleId(sm.getId(), knownKey1).get();
@@ -810,10 +804,11 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final String updateValue = "valueForUpdate";
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
softwareModuleManagement.createMetaData(sm.getId(),
entityFactory.generateMetadata(knownKey, knownValue));
softwareModuleManagement.createMetaData(
entityFactory.softwareModuleMetadata().create(sm.getId()).key(knownKey).value(knownValue));
final JSONObject jsonObject = new JSONObject().put("key", knownKey).put("value", updateValue);
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)
@@ -824,6 +819,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final SoftwareModuleMetadata assertDS = softwareModuleManagement
.getMetaDataBySoftwareModuleId(sm.getId(), knownKey).get();
assertThat(assertDS.getValue()).as("Metadata is wrong").isEqualTo(updateValue);
assertThat(assertDS.isTargetVisible()).as("target visible is wrong").isTrue();
}
@Test
@@ -834,8 +830,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final String knownValue = "knownValue";
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
softwareModuleManagement.createMetaData(sm.getId(),
entityFactory.generateMetadata(knownKey, knownValue));
softwareModuleManagement.createMetaData(
entityFactory.softwareModuleMetadata().create(sm.getId()).key(knownKey).value(knownValue));
mvc.perform(delete("/rest/v1/softwaremodules/{swId}/metadata/{key}", sm.getId(), knownKey))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
@@ -851,8 +847,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final String knownValue = "knownValue";
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
softwareModuleManagement.createMetaData(sm.getId(),
entityFactory.generateMetadata(knownKey, knownValue));
softwareModuleManagement.createMetaData(
entityFactory.softwareModuleMetadata().create(sm.getId()).key(knownKey).value(knownValue));
mvc.perform(delete("/rest/v1/softwaremodules/{swId}/metadata/XXX", sm.getId(), knownKey))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
@@ -879,8 +875,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
for (int index = 0; index < totalMetadata; index++) {
softwareModuleManagement.createMetaData(sm.getId(),
entityFactory.generateMetadata(knownKeyPrefix + index, knownValuePrefix + index));
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(sm.getId())
.key(knownKeyPrefix + index).value(knownValuePrefix + index));
}
final String rsqlSearchValue1 = "value==knownValue1";

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.repository;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -25,6 +26,7 @@ import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.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.TenantConfigurationProperties.TenantConfigurationKey;
@@ -72,7 +74,20 @@ public interface ControllerManagement {
* @return {@link SoftwareModule} identified by ID
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
Optional<SoftwareModule> getSoftwareModule(@NotNull final Long moduleId);
Optional<SoftwareModule> getSoftwareModule(@NotNull Long moduleId);
/**
* Retrieves {@link SoftwareModuleMetadata} where
* {@link SoftwareModuleMetadata#isTargetVisible()}.
*
* @param moduleId
* of the {@link SoftwareModule}
* @return list of {@link SoftwareModuleMetadata} with maximum size of
* {@link RepositoryConstants#MAX_META_DATA_COUNT}
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
Map<Long, List<SoftwareModuleMetadata>> findTargetVisibleMetaDataBySoftwareModuleId(
@NotNull Collection<Long> moduleId);
/**
* Simple addition of a new {@link ActionStatus} entry to the {@link Action}

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.repository;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.repository.builder.ActionStatusBuilder;
import org.eclipse.hawkbit.repository.builder.DistributionSetBuilder;
@@ -16,13 +17,13 @@ import org.eclipse.hawkbit.repository.builder.DistributionSetTypeBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutGroupBuilder;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleBuilder;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeBuilder;
import org.eclipse.hawkbit.repository.builder.TagBuilder;
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.hibernate.validator.constraints.NotEmpty;
/**
* central {@link BaseEntity} generation service. Objects are created but not
@@ -51,7 +52,13 @@ public interface EntityFactory {
*
* @return {@link MetaData} object
*/
MetaData generateMetadata(@NotEmpty String key, @NotNull String value);
MetaData generateMetadata(@Size(min = 1, max = MetaData.KEY_MAX_SIZE) @NotNull String key,
@Size(min = 1, max = MetaData.VALUE_MAX_SIZE) @NotNull String value);
/**
* @return {@link SoftwareModuleMetadataBuilder} object
*/
SoftwareModuleMetadataBuilder softwareModuleMetadata();
/**
* @return {@link TagBuilder} object

View File

@@ -8,8 +8,10 @@
*/
package org.eclipse.hawkbit.repository;
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;
/**
* Repository constants.
@@ -36,6 +38,13 @@ public final class RepositoryConstants {
*/
public static final int MAX_ACTION_HISTORY_MSG_COUNT = 100;
/**
* Maximum number of metadata entries provided to controllers.
*
* @see SoftwareModuleMetadata#isTargetVisible()
*/
public static final int MAX_META_DATA_COUNT = 50;
private RepositoryConstants() {
// Utility class.
}

View File

@@ -16,6 +16,8 @@ import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
@@ -23,7 +25,6 @@ import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
@@ -60,10 +61,8 @@ public interface SoftwareModuleManagement
/**
* creates a list of software module meta data entries.
*
* @param moduleId
* the metadata belongs to
* @param metadata
* the meta data entries to create or update
* the meta data entries to create
* @return the updated or created software module meta data entries
* @throws EntityAlreadyExistsException
* in case one of the meta data entry already exists for the
@@ -72,15 +71,13 @@ public interface SoftwareModuleManagement
* if software module with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
List<SoftwareModuleMetadata> createMetaData(@NotNull Long moduleId, @NotNull Collection<MetaData> metadata);
List<SoftwareModuleMetadata> createMetaData(@NotNull Collection<SoftwareModuleMetadataCreate> metadata);
/**
* creates or updates a single software module meta data entry.
*
* @param moduleId
* the metadata belongs to
* @param metadata
* the meta data entry to create or update
* 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
@@ -89,7 +86,7 @@ public interface SoftwareModuleManagement
* if software module with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
SoftwareModuleMetadata createMetaData(@NotNull Long moduleId, @NotNull MetaData metadata);
SoftwareModuleMetadata createMetaData(@NotNull SoftwareModuleMetadataCreate metadata);
/**
* deletes a software module meta data entry.
@@ -188,6 +185,25 @@ public interface SoftwareModuleManagement
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleId(@NotNull Pageable pageable, @NotNull Long moduleId);
/**
* finds all meta data by the given software module id where
* {@link SoftwareModuleMetadata#isTargetVisible()}.
*
* @param pageable
* the page request to page the result
* @param moduleId
* 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_AUTH_READ_REPOSITORY)
Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleIdAndTargetVisible(@NotNull Pageable pageable,
@NotNull Long moduleId);
/**
* finds all meta data by the given software module id.
*
@@ -259,9 +275,7 @@ public interface SoftwareModuleManagement
/**
* updates a distribution set meta data value if corresponding entry exists.
*
* @param moduleId
* the metadata belongs to
* @param metadata
* @param update
* the meta data entry to be updated
*
* @return the updated meta data entry
@@ -271,5 +285,5 @@ public interface SoftwareModuleManagement
* updated
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
SoftwareModuleMetadata updateMetaData(@NotNull Long moduleId, @NotNull MetaData metadata);
SoftwareModuleMetadata updateMetaData(@NotNull SoftwareModuleMetadataUpdate update);
}

View File

@@ -57,6 +57,8 @@ public interface SystemManagement {
/**
* Runs consumer for each teant as
* {@link TenantAware#runAsTenant(String, org.eclipse.hawkbit.tenancy.TenantAware.TenantRunner)}
* sliently (i.e. exceptions will be logged but operations will continue for
* further tenants).
*
* @param consumer
* to run as teanant

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.builder;
import org.eclipse.hawkbit.repository.model.MetaData;
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 MetaData} belongs to
* @param key
* of {@link MetaData#getKey()}
* @return builder instance
*/
SoftwareModuleMetadataUpdate update(long softwareModuleId, String key);
/**
* @param softwareModuleId
* of the {@link SoftwareModule} the {@link MetaData} belongs to
* @return builder instance
*/
SoftwareModuleMetadataCreate create(long softwareModuleId);
}

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.builder;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.MetaData;
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 MetaData#getKey()}
* @return updated builder instance
*/
SoftwareModuleMetadataCreate key(@Size(min = 1, max = MetaData.KEY_MAX_SIZE) @NotNull String key);
/**
* @param value
* for {@link MetaData#getValue()}
* @return updated builder instance
*/
SoftwareModuleMetadataCreate value(@Size(min = 1, max = MetaData.VALUE_MAX_SIZE) @NotNull 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();
}

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.builder;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.repository.model.MetaData;
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 MetaData#getValue()}
* @return updated builder instance
*/
SoftwareModuleMetadataUpdate value(@Size(min = 1, max = MetaData.VALUE_MAX_SIZE) @NotNull String value);
/**
* @param visible
* for {@link SoftwareModuleMetadata#isTargetVisible()}
* @return updated builder instance
*/
SoftwareModuleMetadataUpdate targetVisible(Boolean visible);
}

View File

@@ -19,4 +19,9 @@ public interface DistributionSetMetadata extends MetaData {
*/
DistributionSet getDistributionSet();
@Override
default Long getEntityId() {
return getDistributionSet().getId();
}
}

View File

@@ -15,6 +15,20 @@ import java.io.Serializable;
*
*/
public interface MetaData extends Serializable {
/**
* Maximum length of metadata key.
*/
int KEY_MAX_SIZE = 128;
/**
* Maximum length of metadata value.
*/
int VALUE_MAX_SIZE = 4000;
/**
* @return {@link BaseEntity#getId()} the metadata is related to
*/
Long getEntityId();
/**
* @return the key

View File

@@ -18,4 +18,15 @@ public interface SoftwareModuleMetadata extends MetaData {
* @return {@link SoftwareModule} this entry belongs to.
*/
SoftwareModule getSoftwareModule();
@Override
default Long getEntityId() {
return getSoftwareModule().getId();
}
/**
* @return <code>true</code> if element is visible for targets as part of
* {@link Action}.
*/
boolean isTargetVisible();
}

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.builder;
import java.util.Optional;
/**
* Create and update builder DTO.
*
* @param <T>
* update or create builder interface
*/
public abstract class AbstractMetadataUpdateCreate<T> {
protected String key;
protected String value;
public T key(final String key) {
this.key = key;
return (T) this;
}
public String getKey() {
return key;
}
public T value(final String value) {
this.value = value;
return (T) this;
}
public Optional<String> getValue() {
return Optional.ofNullable(value);
}
}

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.builder;
import java.util.Optional;
/**
* Create and update builder DTO.
*
* @param <T>
* update or create builder interface
*/
public abstract class AbstractSoftwareModuleMetadataUpdateCreate<T> extends AbstractMetadataUpdateCreate<T> {
protected Boolean targetVisible;
protected long softwareModuleId;
public T softwareModuleId(final long softwareModuleId) {
this.softwareModuleId = softwareModuleId;
return (T) this;
}
public long getSoftwareModuleId() {
return softwareModuleId;
}
public Optional<Boolean> isTargetVisible() {
return Optional.ofNullable(targetVisible);
}
public T targetVisible(final Boolean targetVisible) {
this.targetVisible = targetVisible;
return (T) this;
}
}

View File

@@ -0,0 +1,23 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.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;
}
}

View File

@@ -9,10 +9,12 @@
package org.eclipse.hawkbit.repository.jpa;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
@@ -45,6 +47,7 @@ import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.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.security.SystemSecurityContext;
@@ -115,6 +118,9 @@ public class JpaControllerManagement implements ControllerManagement {
@Autowired
private AfterTransactionCommitExecutor afterCommit;
@Autowired
private SoftwareModuleMetadataRepository softwareModuleMetadataRepository;
@Override
public String getPollingTime() {
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
@@ -523,4 +529,15 @@ public class JpaControllerManagement implements ControllerManagement {
public Optional<SoftwareModule> getSoftwareModule(final Long id) {
return Optional.ofNullable(softwareModuleRepository.findOne(id));
}
@Override
public Map<Long, List<SoftwareModuleMetadata>> findTargetVisibleMetaDataBySoftwareModuleId(
final Collection<Long> moduleId) {
return softwareModuleMetadataRepository
.findBySoftwareModuleIdInAndTargetVisible(new PageRequest(0, RepositoryConstants.MAX_META_DATA_COUNT),
moduleId, true)
.getContent().stream().collect(Collectors.groupingBy(o -> (Long) o[0],
Collectors.mapping(o -> (SoftwareModuleMetadata) o[1], Collectors.toList())));
}
}

View File

@@ -15,6 +15,7 @@ import org.eclipse.hawkbit.repository.builder.DistributionSetTypeBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutGroupBuilder;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleBuilder;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeBuilder;
import org.eclipse.hawkbit.repository.builder.TagBuilder;
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
@@ -24,7 +25,7 @@ import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupBuilder;
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleTypeBuilder;
import org.eclipse.hawkbit.repository.jpa.builder.JpaTagBuilder;
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetBuilder;
import org.eclipse.hawkbit.repository.jpa.model.JpaMetaData;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@@ -51,9 +52,12 @@ public class JpaEntityFactory implements EntityFactory {
@Autowired
private TargetFilterQueryBuilder targetFilterQueryBuilder;
@Autowired
private SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder;
@Override
public MetaData generateMetadata(final String key, final String value) {
return new JpaMetaData(key, value);
return new JpaDistributionSetMetadata(key, value);
}
@Override
@@ -106,4 +110,9 @@ public class JpaEntityFactory implements EntityFactory {
return new JpaRolloutGroupBuilder();
}
@Override
public SoftwareModuleMetadataBuilder softwareModuleMetadata() {
return softwareModuleMetadataBuilder;
}
}

View File

@@ -28,15 +28,20 @@ import javax.persistence.criteria.Root;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields;
import org.eclipse.hawkbit.repository.builder.GenericSoftwareModuleMetadataUpdate;
import org.eclipse.hawkbit.repository.builder.GenericSoftwareModuleUpdate;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleCreate;
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleMetadataCreate;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
@@ -51,7 +56,6 @@ import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
@@ -61,6 +65,7 @@ import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
@@ -443,15 +448,17 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
@Transactional
@Retryable(include = {
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public SoftwareModuleMetadata createMetaData(final Long moduleId, final MetaData md) {
public SoftwareModuleMetadata createMetaData(final SoftwareModuleMetadataCreate c) {
final JpaSoftwareModuleMetadataCreate create = (JpaSoftwareModuleMetadataCreate) c;
checkAndThrowAlreadyIfSoftwareModuleMetadataExists(moduleId, md);
checkAndThrowAlreadyIfSoftwareModuleMetadataExists(create.getSoftwareModuleId(), create);
touch(create.getSoftwareModuleId());
return softwareModuleMetadataRepository
.save(new JpaSoftwareModuleMetadata(md.getKey(), touch(moduleId), md.getValue()));
return softwareModuleMetadataRepository.save(create.build());
}
private void checkAndThrowAlreadyIfSoftwareModuleMetadataExists(final Long moduleId, final MetaData md) {
private void checkAndThrowAlreadyIfSoftwareModuleMetadataExists(final Long moduleId,
final JpaSoftwareModuleMetadataCreate md) {
if (softwareModuleMetadataRepository.exists(new SwMetadataCompositeKey(moduleId, md.getKey()))) {
throwMetadataKeyAlreadyExists(md.getKey());
}
@@ -461,28 +468,26 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
@Transactional
@Retryable(include = {
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public List<SoftwareModuleMetadata> createMetaData(final Long moduleId, final Collection<MetaData> md) {
md.forEach(meta -> checkAndThrowAlreadyIfSoftwareModuleMetadataExists(moduleId, meta));
public List<SoftwareModuleMetadata> createMetaData(final Collection<SoftwareModuleMetadataCreate> create) {
final JpaSoftwareModule module = touch(moduleId);
return Collections.unmodifiableList(md.stream()
.map(meta -> softwareModuleMetadataRepository
.save(new JpaSoftwareModuleMetadata(meta.getKey(), module, meta.getValue())))
.collect(Collectors.toList()));
return create.stream().map(this::createMetaData).collect(Collectors.toList());
}
@Override
@Transactional
@Retryable(include = {
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public SoftwareModuleMetadata updateMetaData(final Long moduleId, final MetaData md) {
public SoftwareModuleMetadata updateMetaData(final SoftwareModuleMetadataUpdate u) {
final GenericSoftwareModuleMetadataUpdate update = (GenericSoftwareModuleMetadataUpdate) u;
// check if exists otherwise throw entity not found exception
final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) getMetaDataBySoftwareModuleId(moduleId,
md.getKey()).orElseThrow(
() -> new EntityNotFoundException(SoftwareModuleMetadata.class, moduleId, md.getKey()));
metadata.setValue(md.getValue());
final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) getMetaDataBySoftwareModuleId(
update.getSoftwareModuleId(), update.getKey())
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleMetadata.class,
update.getSoftwareModuleId(), update.getKey()));
update.getValue().ifPresent(metadata::setValue);
update.isTargetVisible().ifPresent(metadata::setTargetVisible);
touch(metadata.getSoftwareModule());
return softwareModuleMetadataRepository.save(metadata);
@@ -593,4 +598,13 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
return softwareModuleRepository.exists(id);
}
@Override
public Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleIdAndTargetVisible(final Pageable pageable,
final Long moduleId) {
throwExceptionIfSoftwareModuleDoesNotExist(moduleId);
return convertMdPage(softwareModuleMetadataRepository.findBySoftwareModuleIdAndTargetVisible(
new PageRequest(0, RepositoryConstants.MAX_META_DATA_COUNT), moduleId, true), pageable);
}
}

View File

@@ -34,6 +34,8 @@ import org.eclipse.hawkbit.repository.report.model.SystemUsageReportWithTenants;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.interceptor.KeyGenerator;
@@ -59,6 +61,8 @@ import org.springframework.validation.annotation.Validated;
@Transactional(readOnly = true)
@Validated
public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, SystemManagement {
private static final Logger LOGGER = LoggerFactory.getLogger(JpaSystemManagement.class);
private static final int MAX_TENANTS_QUERY = 500;
@Autowired
@@ -328,7 +332,12 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
do {
tenants = findTenants(query);
tenants.forEach(tenant -> tenantAware.runAsTenant(tenant, () -> {
consumer.accept(tenant);
try {
consumer.accept(tenant);
} catch (final RuntimeException ex) {
LOGGER.error("Exception on forEachTenant execution for tenant {}. Continue with next tenant.",
tenant, ex);
}
return null;
}));
} while (tenants.hasNext() && (query = tenants.nextPageable()) != null);

View File

@@ -39,6 +39,7 @@ import org.eclipse.hawkbit.repository.builder.DistributionSetBuilder;
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleBuilder;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
import org.eclipse.hawkbit.repository.event.ApplicationEventFilter;
import org.eclipse.hawkbit.repository.event.remote.EventEntityManager;
@@ -51,6 +52,7 @@ import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetBuilder;
import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetTypeBuilder;
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutBuilder;
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleBuilder;
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleMetadataBuilder;
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetFilterQueryBuilder;
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager;
@@ -167,6 +169,12 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
return new JpaDistributionSetBuilder(distributionSetTypeManagement, softwareManagement);
}
@Bean
SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder(
final SoftwareModuleManagement softwareModuleManagement) {
return new JpaSoftwareModuleMetadataBuilder(softwareModuleManagement);
}
/**
* @param softwareManagement
* for loading

View File

@@ -38,7 +38,7 @@ public interface RolloutGroupRepository
* the rollout the rolloutgroups belong to
* @return the rollout groups belonging to a rollout ordered by ID ASC.
*/
List<JpaRolloutGroup> findByRolloutOrderByIdAsc(final JpaRollout rollout);
List<JpaRolloutGroup> findByRolloutOrderByIdAsc(JpaRollout rollout);
/**
* Retrieves all {@link RolloutGroup} referring a specific rollout in a
@@ -50,7 +50,7 @@ public interface RolloutGroupRepository
* the status of the rollout groups
* @return the rollout groups belonging to a rollout in a specific status
*/
List<JpaRolloutGroup> findByRolloutAndStatus(final Rollout rollout, final RolloutGroupStatus status);
List<JpaRolloutGroup> findByRolloutAndStatus(Rollout rollout, RolloutGroupStatus status);
/**
* Counts all {@link RolloutGroup} referring a specific rollout in specific

View File

@@ -8,11 +8,17 @@
*/
package org.eclipse.hawkbit.repository.jpa;
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.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
/**
@@ -24,4 +30,11 @@ public interface SoftwareModuleMetadataRepository
extends PagingAndSortingRepository<JpaSoftwareModuleMetadata, SwMetadataCompositeKey>,
JpaSpecificationExecutor<JpaSoftwareModuleMetadata> {
Page<JpaSoftwareModuleMetadata> findBySoftwareModuleIdAndTargetVisible(Pageable page, Long moduleId,
boolean targetVisible);
@Query("SELECT smd.softwareModule.id, smd FROM JpaSoftwareModuleMetadata smd WHERE smd.softwareModule.id IN :moduleId AND smd.targetVisible = :targetVisible")
Page<Object[]> findBySoftwareModuleIdInAndTargetVisible(Pageable page, @Param("moduleId") Collection<Long> moduleId,
@Param("targetVisible") boolean targetVisible);
}

View File

@@ -0,0 +1,40 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.builder;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
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.model.SoftwareModuleMetadata;
/**
* Builder implementation for {@link SoftwareModuleMetadata}.
*
*/
public class JpaSoftwareModuleMetadataBuilder implements SoftwareModuleMetadataBuilder {
private final SoftwareModuleManagement softwareModuleManagement;
public JpaSoftwareModuleMetadataBuilder(final SoftwareModuleManagement 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);
}
}

View File

@@ -0,0 +1,46 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.builder;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
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.model.JpaSoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
/**
* Create/build implementation.
*
*/
public class JpaSoftwareModuleMetadataCreate
extends AbstractSoftwareModuleMetadataUpdateCreate<SoftwareModuleMetadataCreate>
implements SoftwareModuleMetadataCreate {
private final SoftwareModuleManagement softwareModuleManagement;
JpaSoftwareModuleMetadataCreate(final long softwareModuleId,
final SoftwareModuleManagement softwareModuleManagement) {
this.softwareModuleManagement = softwareModuleManagement;
this.softwareModuleId = softwareModuleId;
}
@Override
public JpaSoftwareModuleMetadata build() {
final SoftwareModule 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));
}
}

View File

@@ -12,36 +12,36 @@ import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.hibernate.validator.constraints.NotEmpty;
/**
* Meta data for entities.
*
*/
@MappedSuperclass
public class JpaMetaData implements MetaData {
public abstract class AbstractJpaMetaData implements MetaData {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "meta_key", nullable = false, length = 128)
@Size(min = 1, max = 128)
@NotEmpty
@Column(name = "meta_key", nullable = false, length = MetaData.KEY_MAX_SIZE, updatable = false)
@Size(min = 1, max = MetaData.KEY_MAX_SIZE)
@NotNull
private String key;
@Column(name = "meta_value", length = 4000)
@Size(max = 4000)
@Column(name = "meta_value", length = MetaData.VALUE_MAX_SIZE)
@Size(max = MetaData.VALUE_MAX_SIZE)
@Basic
private String value;
public JpaMetaData(final String key, final String value) {
public AbstractJpaMetaData(final String key, final String value) {
this.key = key;
this.value = value;
}
public JpaMetaData() {
public AbstractJpaMetaData() {
// Default constructor needed for JPA entities
}
@@ -83,7 +83,7 @@ public class JpaMetaData implements MetaData {
if (!(this.getClass().isInstance(obj))) {
return false;
}
final JpaMetaData other = (JpaMetaData) obj;
final AbstractJpaMetaData other = (AbstractJpaMetaData) obj;
if (key == null) {
if (other.key != null) {
return false;

View File

@@ -28,7 +28,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
@IdClass(DsMetadataCompositeKey.class)
@Entity
@Table(name = "sp_ds_metadata")
public class JpaDistributionSetMetadata extends JpaMetaData implements DistributionSetMetadata {
public class JpaDistributionSetMetadata extends AbstractJpaMetaData implements DistributionSetMetadata {
private static final long serialVersionUID = 1L;
@Id
@@ -40,6 +40,10 @@ public class JpaDistributionSetMetadata extends JpaMetaData implements Distribut
// default public constructor for JPA
}
public JpaDistributionSetMetadata(final String key, final String value) {
super(key, value);
}
public JpaDistributionSetMetadata(final String key, final DistributionSet distributionSet, final String value) {
super(key, value);
this.distributionSet = (JpaDistributionSet) distributionSet;

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.FetchType;
@@ -28,7 +29,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
@IdClass(SwMetadataCompositeKey.class)
@Entity
@Table(name = "sp_sw_metadata")
public class JpaSoftwareModuleMetadata extends JpaMetaData implements SoftwareModuleMetadata {
public class JpaSoftwareModuleMetadata extends AbstractJpaMetaData implements SoftwareModuleMetadata {
private static final long serialVersionUID = 1L;
@Id
@@ -36,6 +37,9 @@ public class JpaSoftwareModuleMetadata extends JpaMetaData implements SoftwareMo
@JoinColumn(name = "sw_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_metadata_sw"))
private JpaSoftwareModule softwareModule;
@Column(name = "target_visible")
private boolean targetVisible;
public JpaSoftwareModuleMetadata() {
// default public constructor for JPA
}
@@ -45,6 +49,18 @@ public class JpaSoftwareModuleMetadata extends JpaMetaData implements SoftwareMo
this.softwareModule = (JpaSoftwareModule) softwareModule;
}
public JpaSoftwareModuleMetadata(final String key, final SoftwareModule softwareModule, final String value,
final boolean targetVisible) {
super(key, value);
this.softwareModule = (JpaSoftwareModule) softwareModule;
this.targetVisible = targetVisible;
}
public JpaSoftwareModuleMetadata(final String key, final String value, final boolean targetVisible) {
super(key, value);
this.targetVisible = targetVisible;
}
public SwMetadataCompositeKey getId() {
return new SwMetadataCompositeKey(softwareModule.getId(), getKey());
}
@@ -58,6 +74,15 @@ public class JpaSoftwareModuleMetadata extends JpaMetaData implements SoftwareMo
this.softwareModule = softwareModule;
}
@Override
public boolean isTargetVisible() {
return targetVisible;
}
public void setTargetVisible(final boolean targetVisible) {
this.targetVisible = targetVisible;
}
@Override
public int hashCode() {
final int prime = 31;
@@ -83,4 +108,5 @@ public class JpaSoftwareModuleMetadata extends JpaMetaData implements SoftwareMo
}
return true;
}
}

View File

@@ -0,0 +1 @@
ALTER TABLE sp_sw_metadata ADD COLUMN target_visible boolean;

View File

@@ -0,0 +1 @@
ALTER TABLE sp_sw_metadata ADD COLUMN target_visible bit;

View File

@@ -17,6 +17,7 @@ import java.io.ByteArrayInputStream;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.validation.ConstraintViolationException;
@@ -40,6 +41,7 @@ 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;
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;
@@ -432,6 +434,23 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
.as("register target with empty controllerId should fail");
}
@Test
@Description("Verify that targetVisible metadata is returned from repository")
@ExpectEvents({ @Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6) })
public void findTargetVisibleMetaDataBySoftwareModuleId() {
final DistributionSet set = testdataFactory.createDistributionSet();
testdataFactory.addSoftwareModuleMetadata(set);
final Map<Long, List<SoftwareModuleMetadata>> result = controllerManagement
.findTargetVisibleMetaDataBySoftwareModuleId(
set.getModules().stream().map(SoftwareModule::getId).collect(Collectors.toList()));
assertThat(result).hasSize(3);
result.entrySet().forEach(entry -> assertThat(entry.getValue()).hasSize(1));
}
@Test
@Description("Verify that controller registration does not result in a TargetPollEvent if feature is disabled")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),

View File

@@ -747,19 +747,17 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
@Description("Queries and loads the metadata related to a given software module.")
public void findAllDistributionSetMetadataByDsId() {
// create a DS
DistributionSet ds1 = testdataFactory.createDistributionSet("testDs1");
DistributionSet ds2 = testdataFactory.createDistributionSet("testDs2");
final DistributionSet ds1 = testdataFactory.createDistributionSet("testDs1");
final DistributionSet ds2 = testdataFactory.createDistributionSet("testDs2");
for (int index = 0; index < 10; index++) {
ds1 = createDistributionSetMetadata(ds1.getId(),
new JpaDistributionSetMetadata("key" + index, ds1, "value" + index)).getDistributionSet();
createDistributionSetMetadata(ds1.getId(),
new JpaDistributionSetMetadata("key" + index, ds1, "value" + index));
}
for (int index = 0; index < 20; index++) {
ds2 = createDistributionSetMetadata(ds2.getId(),
new JpaDistributionSetMetadata("key" + index, ds2, "value" + index)).getDistributionSet();
createDistributionSetMetadata(ds2.getId(),
new JpaDistributionSetMetadata("key" + index, ds2, "value" + index));
}
final Page<DistributionSetMetadata> metadataOfDs1 = distributionSetManagement

View File

@@ -9,17 +9,18 @@
package org.eclipse.hawkbit.repository.jpa;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
@@ -84,10 +85,14 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
.create(entityFactory.softwareModule().create().name("xxx").type(NOT_EXIST_ID)),
"SoftwareModuleType");
verifyThrownExceptionBy(() -> softwareModuleManagement.createMetaData(NOT_EXIST_IDL,
entityFactory.generateMetadata("xxx", "xxx")), "SoftwareModule");
verifyThrownExceptionBy(() -> softwareModuleManagement.createMetaData(NOT_EXIST_IDL,
Arrays.asList(entityFactory.generateMetadata("xxx", "xxx"))), "SoftwareModule");
verifyThrownExceptionBy(
() -> softwareModuleManagement.createMetaData(
entityFactory.softwareModuleMetadata().create(NOT_EXIST_IDL).key("xxx").value("xxx")),
"SoftwareModule");
verifyThrownExceptionBy(
() -> softwareModuleManagement.createMetaData(Arrays
.asList(entityFactory.softwareModuleMetadata().create(NOT_EXIST_IDL).key("xxx").value("xxx"))),
"SoftwareModule");
verifyThrownExceptionBy(() -> softwareModuleManagement.delete(NOT_EXIST_IDL), "SoftwareModule");
verifyThrownExceptionBy(() -> softwareModuleManagement.delete(Arrays.asList(NOT_EXIST_IDL)), "SoftwareModule");
@@ -95,10 +100,14 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
verifyThrownExceptionBy(() -> softwareModuleManagement.deleteMetaData(module.getId(), NOT_EXIST_ID),
"SoftwareModuleMetadata");
verifyThrownExceptionBy(() -> softwareModuleManagement.updateMetaData(NOT_EXIST_IDL,
entityFactory.generateMetadata("xxx", "xxx")), "SoftwareModule");
verifyThrownExceptionBy(() -> softwareModuleManagement.updateMetaData(module.getId(),
entityFactory.generateMetadata(NOT_EXIST_ID, "xxx")), "SoftwareModuleMetadata");
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");
verifyThrownExceptionBy(() -> softwareModuleManagement.findByAssignedTo(PAGE, NOT_EXIST_IDL),
"DistributionSet");
@@ -624,12 +633,14 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
assertThat(ah.getOptLockRevision()).isEqualTo(1);
final SoftwareModuleMetadata swMetadata1 = new JpaSoftwareModuleMetadata(knownKey1, ah, knownValue1);
final SoftwareModuleMetadataCreate swMetadata1 = entityFactory.softwareModuleMetadata().create(ah.getId())
.key(knownKey1).value(knownValue1);
final SoftwareModuleMetadata swMetadata2 = new JpaSoftwareModuleMetadata(knownKey2, ah, knownValue2);
final SoftwareModuleMetadataCreate swMetadata2 = entityFactory.softwareModuleMetadata().create(ah.getId())
.key(knownKey2).value(knownValue2);
final List<SoftwareModuleMetadata> softwareModuleMetadata = softwareModuleManagement.createMetaData(ah.getId(),
Arrays.asList(swMetadata1, swMetadata2));
final List<SoftwareModuleMetadata> softwareModuleMetadata = softwareModuleManagement
.createMetaData(Arrays.asList(swMetadata1, swMetadata2));
final SoftwareModule changedLockRevisionModule = softwareModuleManagement.get(ah.getId()).get();
assertThat(changedLockRevisionModule.getOptLockRevision()).isEqualTo(2);
@@ -638,7 +649,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
assertThat(softwareModuleMetadata.get(0)).isNotNull();
assertThat(softwareModuleMetadata.get(0).getValue()).isEqualTo(knownValue1);
assertThat(((JpaSoftwareModuleMetadata) softwareModuleMetadata.get(0)).getId().getKey()).isEqualTo(knownKey1);
assertThat(softwareModuleMetadata.get(0).getSoftwareModule().getId()).isEqualTo(ah.getId());
assertThat(softwareModuleMetadata.get(0).getEntityId()).isEqualTo(ah.getId());
}
@Test
@@ -651,14 +662,23 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
final SoftwareModule ah = testdataFactory.createSoftwareModuleApp();
softwareModuleManagement.createMetaData(ah.getId(), entityFactory.generateMetadata(knownKey1, knownValue1));
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(ah.getId()).key(knownKey1)
.value(knownValue1).targetVisible(true));
try {
softwareModuleManagement.createMetaData(ah.getId(), entityFactory.generateMetadata(knownKey1, knownValue2));
fail("should not have worked as module metadata already exists");
} catch (final EntityAlreadyExistsException e) {
assertThatExceptionOfType(EntityAlreadyExistsException.class)
.isThrownBy(() -> softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata()
.create(ah.getId()).key(knownKey1).value(knownValue1).targetVisible(true)))
.withMessageContaining("Metadata").withMessageContaining(knownKey1);
}
final String knownKey2 = "myKnownKey2";
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(ah.getId()).key(knownKey2)
.value(knownValue1).targetVisible(false));
assertThatExceptionOfType(EntityAlreadyExistsException.class)
.isThrownBy(() -> softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata()
.create(ah.getId()).key(knownKey2).value(knownValue1).targetVisible(true)))
.withMessageContaining("Metadata").withMessageContaining(knownKey2);
}
@Test
@@ -675,9 +695,11 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
assertThat(ah.getOptLockRevision()).isEqualTo(1);
// create an software module meta data entry
final List<SoftwareModuleMetadata> softwareModuleMetadata = softwareModuleManagement.createMetaData(ah.getId(),
Collections.singleton(entityFactory.generateMetadata(knownKey, knownValue)));
assertThat(softwareModuleMetadata).hasSize(1);
final SoftwareModuleMetadata softwareModuleMetadata = softwareModuleManagement.createMetaData(
entityFactory.softwareModuleMetadata().create(ah.getId()).key(knownKey).value(knownValue));
assertThat(softwareModuleMetadata.isTargetVisible()).isFalse();
assertThat(softwareModuleMetadata.getValue()).isEqualTo(knownValue);
// base software module should have now the opt lock revision one
// because we are modifying the
// base software module
@@ -686,8 +708,8 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
// update the software module metadata
Thread.sleep(100);
final SoftwareModuleMetadata updated = softwareModuleManagement.updateMetaData(ah.getId(),
entityFactory.generateMetadata(knownKey, knownUpdateValue));
final SoftwareModuleMetadata updated = softwareModuleManagement.updateMetaData(entityFactory
.softwareModuleMetadata().update(ah.getId(), knownKey).value(knownUpdateValue).targetVisible(true));
// we are updating the sw meta data so also modiying the base software
// module so opt lock
// revision must be two
@@ -697,8 +719,9 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
// verify updated meta data contains the updated value
assertThat(updated).isNotNull();
assertThat(updated.getValue()).isEqualTo(knownUpdateValue);
assertThat(updated.isTargetVisible()).isTrue();
assertThat(((JpaSoftwareModuleMetadata) updated).getId().getKey()).isEqualTo(knownKey);
assertThat(updated.getSoftwareModule().getId()).isEqualTo(ah.getId());
assertThat(updated.getEntityId()).isEqualTo(ah.getId());
}
@Test
@@ -709,8 +732,10 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
SoftwareModule ah = testdataFactory.createSoftwareModuleApp();
ah = softwareModuleManagement.createMetaData(ah.getId(), entityFactory.generateMetadata(knownKey1, knownValue1))
.getSoftwareModule();
softwareModuleManagement.createMetaData(
entityFactory.softwareModuleMetadata().create(ah.getId()).key(knownKey1).value(knownValue1));
ah = softwareModuleManagement.get(ah.getId()).get();
assertThat(softwareModuleManagement.findMetaDataBySoftwareModuleId(new PageRequest(0, 10), ah.getId())
.getContent()).as("Contains the created metadata element")
@@ -727,10 +752,10 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
final String knownKey1 = "myKnownKey1";
final String knownValue1 = "myKnownValue1";
SoftwareModule ah = testdataFactory.createSoftwareModuleApp();
final SoftwareModule ah = testdataFactory.createSoftwareModuleApp();
ah = softwareModuleManagement.createMetaData(ah.getId(), entityFactory.generateMetadata(knownKey1, knownValue1))
.getSoftwareModule();
softwareModuleManagement.createMetaData(
entityFactory.softwareModuleMetadata().create(ah.getId()).key(knownKey1).value(knownValue1));
assertThat(softwareModuleManagement.getMetaDataBySoftwareModuleId(ah.getId(), "doesnotexist")).isNotPresent();
}
@@ -739,26 +764,24 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
@Description("Queries and loads the metadata related to a given software module.")
public void findAllSoftwareModuleMetadataBySwId() {
SoftwareModule sw1 = testdataFactory.createSoftwareModuleApp();
final SoftwareModule sw1 = testdataFactory.createSoftwareModuleApp();
SoftwareModule sw2 = testdataFactory.createSoftwareModuleOs();
final SoftwareModule sw2 = testdataFactory.createSoftwareModuleOs();
for (int index = 0; index < 10; index++) {
sw1 = softwareModuleManagement
.createMetaData(sw1.getId(), entityFactory.generateMetadata("key" + index, "value" + index))
.getSoftwareModule();
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(sw1.getId())
.key("key" + index).value("value" + index).targetVisible(true));
}
for (int index = 0; index < 20; index++) {
sw2 = softwareModuleManagement
.createMetaData(sw2.getId(), new JpaSoftwareModuleMetadata("key" + index, sw2, "value" + index))
.getSoftwareModule();
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(sw2.getId())
.key("key" + index).value("value" + index).targetVisible(false));
}
final Page<SoftwareModuleMetadata> metadataOfSw1 = softwareModuleManagement
Page<SoftwareModuleMetadata> metadataOfSw1 = softwareModuleManagement
.findMetaDataBySoftwareModuleId(new PageRequest(0, 100), sw1.getId());
final Page<SoftwareModuleMetadata> metadataOfSw2 = softwareModuleManagement
Page<SoftwareModuleMetadata> metadataOfSw2 = softwareModuleManagement
.findMetaDataBySoftwareModuleId(new PageRequest(0, 100), sw2.getId());
assertThat(metadataOfSw1.getNumberOfElements()).isEqualTo(10);
@@ -766,5 +789,17 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
assertThat(metadataOfSw2.getNumberOfElements()).isEqualTo(20);
assertThat(metadataOfSw2.getTotalElements()).isEqualTo(20);
metadataOfSw1 = softwareModuleManagement.findMetaDataBySoftwareModuleIdAndTargetVisible(new PageRequest(0, 100),
sw1.getId());
metadataOfSw2 = softwareModuleManagement.findMetaDataBySoftwareModuleIdAndTargetVisible(new PageRequest(0, 100),
sw2.getId());
assertThat(metadataOfSw1.getNumberOfElements()).isEqualTo(10);
assertThat(metadataOfSw1.getTotalElements()).isEqualTo(10);
assertThat(metadataOfSw2.getNumberOfElements()).isEqualTo(0);
assertThat(metadataOfSw2.getTotalElements()).isEqualTo(0);
}
}

View File

@@ -11,9 +11,9 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat;
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
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.MetaData;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.junit.Before;
@@ -31,21 +31,23 @@ public class RSQLSoftwareModuleFieldTest extends AbstractJpaIntegrationTest {
@Before
public void setupBeforeTest() {
final SoftwareModule ah = softwareModuleManagement.create(entityFactory.softwareModule().create()
.type(appType).name("agent-hub").version("1.0.1").description("agent-hub"));
softwareModuleManagement.create(entityFactory.softwareModule().create().type(runtimeType)
.name("oracle-jre").version("1.7.2").description("aa"));
final SoftwareModule ah = softwareModuleManagement.create(entityFactory.softwareModule().create().type(appType)
.name("agent-hub").version("1.0.1").description("agent-hub"));
softwareModuleManagement.create(entityFactory.softwareModule().create().type(runtimeType).name("oracle-jre")
.version("1.7.2").description("aa"));
softwareModuleManagement.create(
entityFactory.softwareModule().create().type(osType).name("poky").version("3.0.2").description("aa"));
final JpaSoftwareModule ah2 = (JpaSoftwareModule) softwareModuleManagement.create(entityFactory
.softwareModule().create().type(appType).name("agent-hub2").version("1.0.1").description("agent-hub2"));
final JpaSoftwareModule ah2 = (JpaSoftwareModule) softwareModuleManagement.create(entityFactory.softwareModule()
.create().type(appType).name("agent-hub2").version("1.0.1").description("agent-hub2"));
final MetaData softwareModuleMetadata = entityFactory.generateMetadata("metaKey", "metaValue");
softwareModuleManagement.createMetaData(ah.getId(), softwareModuleMetadata);
final SoftwareModuleMetadataCreate softwareModuleMetadata = entityFactory.softwareModuleMetadata()
.create(ah.getId()).key("metaKey").value("metaValue");
softwareModuleManagement.createMetaData(softwareModuleMetadata);
final MetaData softwareModuleMetadata2 = entityFactory.generateMetadata("metaKey", "value");
softwareModuleManagement.createMetaData(ah2.getId(), softwareModuleMetadata2);
final SoftwareModuleMetadataCreate softwareModuleMetadata2 = entityFactory.softwareModuleMetadata()
.create(ah2.getId()).key("metaKey").value("value");
softwareModuleManagement.createMetaData(softwareModuleMetadata2);
}
@Test
@@ -105,8 +107,7 @@ public class RSQLSoftwareModuleFieldTest extends AbstractJpaIntegrationTest {
}
private void assertRSQLQuery(final String rsqlParam, final long excpectedEntity) {
final Page<SoftwareModule> find = softwareModuleManagement.findByRsql(new PageRequest(0, 100),
rsqlParam);
final Page<SoftwareModule> find = softwareModuleManagement.findByRsql(new PageRequest(0, 100), rsqlParam);
final long countAll = find.getTotalElements();
assertThat(find).isNotNull();
assertThat(countAll).isEqualTo(excpectedEntity);

View File

@@ -10,12 +10,11 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
@@ -24,6 +23,8 @@ import org.junit.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import com.google.common.collect.Lists;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@@ -40,12 +41,16 @@ public class RSQLSoftwareModuleMetadataFieldsTest extends AbstractJpaIntegration
softwareModuleId = softwareModule.getId();
final List<MetaData> metadata = new ArrayList<>(5);
final List<SoftwareModuleMetadataCreate> metadata = Lists.newArrayListWithExpectedSize(5);
for (int i = 0; i < 5; i++) {
metadata.add(entityFactory.generateMetadata("" + i, "" + i));
metadata.add(
entityFactory.softwareModuleMetadata().create(softwareModule.getId()).key("" + i).value("" + i));
}
softwareModuleManagement.createMetaData(softwareModule.getId(), metadata);
metadata.add(entityFactory.softwareModuleMetadata().create(softwareModule.getId()).key("targetVisible")
.value("targetVisible").targetVisible(true));
softwareModuleManagement.createMetaData(metadata);
}
@@ -53,18 +58,27 @@ public class RSQLSoftwareModuleMetadataFieldsTest extends AbstractJpaIntegration
@Description("Test filter software module metadata by key")
public void testFilterByParameterKey() {
assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "==1", 1);
assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "!=1", 4);
assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "!=1", 5);
assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "=in=(1,2)", 2);
assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "=out=(1,2)", 3);
assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "=out=(1,2)", 4);
}
@Test
@Description("Test fitler software module metadata status by value")
@Description("Test fitler software module metadata by value")
public void testFilterByParameterValue() {
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "==1", 1);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "!=1", 4);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "!=1", 5);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=in=(1,2)", 2);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=out=(1,2)", 3);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=out=(1,2)", 4);
}
@Test
@Description("Test fitler software module metadata by target visible")
public void testFilterByParameterTargetVisible() {
assertRSQLQuery(SoftwareModuleMetadataFields.TARGETVISIBLE.name() + "==true", 1);
assertRSQLQuery(SoftwareModuleMetadataFields.TARGETVISIBLE.name() + "==false", 5);
assertRSQLQuery(SoftwareModuleMetadataFields.TARGETVISIBLE.name() + "!=false", 1);
assertRSQLQuery(SoftwareModuleMetadataFields.TARGETVISIBLE.name() + "!=true", 5);
}
private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {

View File

@@ -54,6 +54,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.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag;
@@ -71,6 +72,11 @@ import net._01001111.text.LoremIpsum;
public class TestdataFactory {
private static final LoremIpsum LOREM = new LoremIpsum();
public static final String VISIBLE_SM_MD_KEY = "visibleMetdataKey";
public static final String VISIBLE_SM_MD_VALUE = "visibleMetdataValue";
public static final String INVISIBLE_SM_MD_KEY = "invisibleMetdataKey";
public static final String INVISIBLE_SM_MD_VALUE = "invisibleMetdataValue";
/**
* default {@link Target#getControllerId()}.
*/
@@ -266,16 +272,16 @@ public class TestdataFactory {
public DistributionSet createDistributionSet(final String prefix, final String version,
final boolean isRequiredMigrationStep) {
final SoftwareModule appMod = softwareModuleManagement.create(entityFactory.softwareModule()
.create().type(findOrCreateSoftwareModuleType(SM_TYPE_APP, Integer.MAX_VALUE))
.name(prefix + SM_TYPE_APP).version(version + "." + new SecureRandom().nextInt(100))
.description(LOREM.words(20)).vendor(prefix + " vendor Limited, California"));
final SoftwareModule runtimeMod = softwareModuleManagement.create(
entityFactory.softwareModule().create().type(findOrCreateSoftwareModuleType(SM_TYPE_RT))
final SoftwareModule appMod = softwareModuleManagement.create(entityFactory.softwareModule().create()
.type(findOrCreateSoftwareModuleType(SM_TYPE_APP, Integer.MAX_VALUE)).name(prefix + SM_TYPE_APP)
.version(version + "." + new SecureRandom().nextInt(100)).description(LOREM.words(20))
.vendor(prefix + " vendor Limited, California"));
final SoftwareModule runtimeMod = softwareModuleManagement
.create(entityFactory.softwareModule().create().type(findOrCreateSoftwareModuleType(SM_TYPE_RT))
.name(prefix + "app runtime").version(version + "." + new SecureRandom().nextInt(100))
.description(LOREM.words(20)).vendor(prefix + " vendor GmbH, Stuttgart, Germany"));
final SoftwareModule osMod = softwareModuleManagement.create(
entityFactory.softwareModule().create().type(findOrCreateSoftwareModuleType(SM_TYPE_OS))
final SoftwareModule osMod = softwareModuleManagement
.create(entityFactory.softwareModule().create().type(findOrCreateSoftwareModuleType(SM_TYPE_OS))
.name(prefix + " Firmware").version(version + "." + new SecureRandom().nextInt(100))
.description(LOREM.words(20)).vendor(prefix + " vendor Limited Inc, California"));
@@ -286,6 +292,30 @@ public class TestdataFactory {
.requiredMigrationStep(isRequiredMigrationStep));
}
/**
* Adds {@link SoftwareModuleMetadata} to every module of given
* {@link DistributionSet}.
*
* {@link #VISIBLE_SM_MD_VALUE}, {@link #VISIBLE_SM_MD_KEY} with
* {@link SoftwareModuleMetadata#isTargetVisible()} and
* {@link #INVISIBLE_SM_MD_KEY}, {@link #INVISIBLE_SM_MD_VALUE} without
* {@link SoftwareModuleMetadata#isTargetVisible()}
*
* @param set
* to add metadata to
*/
public void addSoftwareModuleMetadata(final DistributionSet set) {
set.getModules().forEach(this::addTestModuleMetadata);
}
private void addTestModuleMetadata(final SoftwareModule module) {
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(module.getId())
.key(VISIBLE_SM_MD_KEY).value(VISIBLE_SM_MD_VALUE).targetVisible(true));
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(module.getId())
.key(INVISIBLE_SM_MD_KEY).value(INVISIBLE_SM_MD_VALUE).targetVisible(false));
}
/**
* Creates {@link DistributionSet} in repository.
*
@@ -370,8 +400,8 @@ public class TestdataFactory {
final List<DistributionSet> sets = Lists.newArrayListWithExpectedSize(number);
for (int i = 0; i < number; i++) {
sets.add(distributionSetManagement.create(
entityFactory.distributionSet().create().name("DS" + i).version(DEFAULT_VERSION + "." + i)
sets.add(distributionSetManagement
.create(entityFactory.distributionSet().create().name("DS" + i).version(DEFAULT_VERSION + "." + i)
.description(LOREM.words(10)).type(findOrCreateDefaultTestDsType())));
}
@@ -417,8 +447,8 @@ public class TestdataFactory {
*/
public DistributionSet createDistributionSetWithNoSoftwareModules(final String name, final String version) {
return distributionSetManagement.create(entityFactory.distributionSet().create().name(name)
.version(version).description(DEFAULT_DESCRIPTION).type(findOrCreateDefaultTestDsType()));
return distributionSetManagement.create(entityFactory.distributionSet().create().name(name).version(version)
.description(DEFAULT_DESCRIPTION).type(findOrCreateDefaultTestDsType()));
}
/**
@@ -608,9 +638,9 @@ public class TestdataFactory {
* @return persisted {@link DistributionSetType}
*/
public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKey, final String dsTypeName) {
return distributionSetTypeManagement.getByKey(dsTypeKey).orElseGet(
() -> distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key(dsTypeKey).name(dsTypeName).description(LOREM.words(10)).colour("black")));
return distributionSetTypeManagement.getByKey(dsTypeKey)
.orElseGet(() -> distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
.key(dsTypeKey).name(dsTypeName).description(LOREM.words(10)).colour("black")));
}
/**
@@ -631,9 +661,8 @@ public class TestdataFactory {
public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKey, final String dsTypeName,
final Collection<SoftwareModuleType> mandatory, final Collection<SoftwareModuleType> optional) {
return distributionSetTypeManagement.getByKey(dsTypeKey)
.orElseGet(() -> distributionSetTypeManagement.create(entityFactory
.distributionSetType().create().key(dsTypeKey).name(dsTypeName).description(LOREM.words(10))
.colour("black")
.orElseGet(() -> distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
.key(dsTypeKey).name(dsTypeName).description(LOREM.words(10)).colour("black")
.optional(optional.stream().map(SoftwareModuleType::getId).collect(Collectors.toList()))
.mandatory(mandatory.stream().map(SoftwareModuleType::getId).collect(Collectors.toList()))));
}
@@ -664,8 +693,8 @@ public class TestdataFactory {
* @return persisted {@link SoftwareModuleType}
*/
public SoftwareModuleType findOrCreateSoftwareModuleType(final String key, final int maxAssignments) {
return softwareModuleTypeManagement.getByKey(key).orElseGet(
() -> softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create()
return softwareModuleTypeManagement.getByKey(key)
.orElseGet(() -> softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create()
.key(key).name(key).description(LOREM.words(10)).maxAssignments(maxAssignments)));
}

View File

@@ -12,7 +12,6 @@ import java.io.Serializable;
import org.eclipse.hawkbit.im.authentication.PermissionService;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Bean which contains all SP permissions.
@@ -23,7 +22,6 @@ public class SpPermissionChecker implements Serializable {
protected transient PermissionService permissionService;
@Autowired
protected SpPermissionChecker(final PermissionService permissionService) {
this.permissionService = permissionService;
}
@@ -52,7 +50,7 @@ public class SpPermissionChecker implements Serializable {
* @return TARGET_REPOSITORY_READ boolean value
*/
public boolean hasTargetAndRepositoryReadPermission() {
return hasTargetReadPermission() && hasReadDistributionPermission();
return hasTargetReadPermission() && hasReadRepositoryPermission();
}
/**
@@ -92,39 +90,39 @@ public class SpPermissionChecker implements Serializable {
}
/**
* Gets the SP READ Distribution Permission.
* Gets the SP READ Repository Permission.
*
* @return READ_REPOSITORY boolean value
*/
public boolean hasReadDistributionPermission() {
public boolean hasReadRepositoryPermission() {
return permissionService.hasPermission(SpPermission.READ_REPOSITORY);
}
/**
* Gets the SP create Distribution Permission.
* Gets the SP create Repository Permission.
*
* @return CREATE_REPOSITORY boolean value
*/
public boolean hasCreateDistributionPermission() {
return hasReadDistributionPermission() && permissionService.hasPermission(SpPermission.CREATE_REPOSITORY);
public boolean hasCreateRepositoryPermission() {
return hasReadRepositoryPermission() && permissionService.hasPermission(SpPermission.CREATE_REPOSITORY);
}
/**
* Gets the SP update Distribution Permission.
* Gets the SP update Repository Permission.
*
* @return UPDATE_REPOSITORY boolean value
*/
public boolean hasUpdateDistributionPermission() {
return hasReadDistributionPermission() && permissionService.hasPermission(SpPermission.UPDATE_REPOSITORY);
public boolean hasUpdateRepositoryPermission() {
return hasReadRepositoryPermission() && permissionService.hasPermission(SpPermission.UPDATE_REPOSITORY);
}
/**
* Gets the SP delete Distribution Permission.
* Gets the SP delete Repository Permission.
*
* @return DELETE_REPOSITORY boolean value
*/
public boolean hasDeleteDistributionPermission() {
return hasReadDistributionPermission() && permissionService.hasPermission(SpPermission.DELETE_REPOSITORY);
public boolean hasDeleteRepositoryPermission() {
return hasReadRepositoryPermission() && permissionService.hasPermission(SpPermission.DELETE_REPOSITORY);
}
/**
@@ -133,7 +131,7 @@ public class SpPermissionChecker implements Serializable {
* @return permission for rollout update
*/
public boolean hasRolloutUpdatePermission() {
return hasUpdateTargetPermission() && hasReadDistributionPermission()
return hasUpdateTargetPermission() && hasReadRepositoryPermission()
&& permissionService.hasPermission(SpPermission.ROLLOUT_MANAGEMENT);
}
@@ -143,7 +141,7 @@ public class SpPermissionChecker implements Serializable {
* @return permission for rollout create
*/
public boolean hasRolloutCreatePermission() {
return hasUpdateTargetPermission() && hasReadDistributionPermission()
return hasUpdateTargetPermission() && hasReadRepositoryPermission()
&& permissionService.hasPermission(SpPermission.ROLLOUT_MANAGEMENT);
}

View File

@@ -157,7 +157,7 @@ public class UploadArtifactView extends VerticalLayout implements View, BrowserW
}
private void buildLayout() {
if (permChecker.hasReadDistributionPermission() || permChecker.hasCreateDistributionPermission()) {
if (permChecker.hasReadRepositoryPermission() || permChecker.hasCreateRepositoryPermission()) {
setSizeFull();
createMainLayout();
addComponents(mainLayout);
@@ -170,7 +170,7 @@ public class UploadArtifactView extends VerticalLayout implements View, BrowserW
detailAndUploadLayout.addComponent(artifactDetailsLayout);
detailAndUploadLayout.setComponentAlignment(artifactDetailsLayout, Alignment.MIDDLE_CENTER);
if (permChecker.hasCreateDistributionPermission()) {
if (permChecker.hasCreateRepositoryPermission()) {
dadw = uploadLayout.getDropAreaWrapper();
detailAndUploadLayout.addComponent(dadw);
detailAndUploadLayout.setComponentAlignment(dadw, Alignment.MIDDLE_CENTER);
@@ -204,7 +204,7 @@ public class UploadArtifactView extends VerticalLayout implements View, BrowserW
private void createUploadButtonLayout() {
uplaodButtonsLayout = new HorizontalLayout();
if (permChecker.hasCreateDistributionPermission()) {
if (permChecker.hasCreateRepositoryPermission()) {
uplaodButtonsLayout = uploadLayout.getFileUploadLayout();
}
}

View File

@@ -92,7 +92,7 @@ public class SMDeleteActionsLayout extends AbstractDeleteActionsLayout {
@Override
protected boolean hasDeletePermission() {
return permChecker.hasDeleteDistributionPermission();
return permChecker.hasDeleteRepositoryPermission();
}
@Override

View File

@@ -8,7 +8,6 @@
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
@@ -31,8 +30,8 @@ public class SoftwareModuleDetails extends AbstractSoftwareModuleDetails {
final SpPermissionChecker permissionChecker,
final SoftwareModuleAddUpdateWindow softwareModuleAddUpdateWindow,
final ArtifactUploadState artifactUploadState, final SoftwareModuleManagement softwareManagement,
final SwMetadataPopupLayout swMetadataPopupLayout, final EntityFactory entityFactory) {
super(i18n, eventBus, permissionChecker, null, softwareManagement, swMetadataPopupLayout, entityFactory,
final SwMetadataPopupLayout swMetadataPopupLayout) {
super(i18n, eventBus, permissionChecker, null, softwareManagement, swMetadataPopupLayout,
softwareModuleAddUpdateWindow);
this.artifactUploadState = artifactUploadState;
restoreState();

View File

@@ -49,7 +49,7 @@ public class SoftwareModuleTableLayout extends AbstractTableLayout<SoftwareModul
softwareModuleAddUpdateWindow),
softwareModuleTable,
new SoftwareModuleDetails(i18n, eventBus, permChecker, softwareModuleAddUpdateWindow,
artifactUploadState, softwareModuleManagement, swMetadataPopupLayout, entityFactory));
artifactUploadState, softwareModuleManagement, swMetadataPopupLayout));
}
public SoftwareModuleTable getSoftwareModuleTable() {

View File

@@ -43,14 +43,14 @@ public class SMTypeFilterHeader extends AbstractFilterHeader {
this.createUpdateSWTypeLayout = new CreateUpdateSoftwareTypeLayout(i18n, entityFactory, eventBus, permChecker,
uiNotification, softwareModuletypeManagement);
if (permChecker.hasCreateDistributionPermission() || permChecker.hasUpdateDistributionPermission()) {
if (permChecker.hasCreateRepositoryPermission() || permChecker.hasUpdateRepositoryPermission()) {
createUpdateSWTypeLayout.init();
}
}
@Override
protected boolean hasCreateUpdatePermission() {
return permChecker.hasCreateDistributionPermission() || permChecker.hasUpdateDistributionPermission();
return permChecker.hasCreateRepositoryPermission() || permChecker.hasUpdateRepositoryPermission();
}
@Override

View File

@@ -67,9 +67,9 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
private static final long serialVersionUID = -1491218218453167613L;
private static final String VALUE = "value";
protected static final String VALUE = "value";
private static final String KEY = "key";
protected static final String KEY = "key";
protected static final int MAX_METADATA_QUERY = 500;
@@ -133,11 +133,11 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
*
* @param entity
* entity for which metadata data is displayed
* @param metaData
* metadata to be selected
* @param metaDatakey
* metadata key to be selected
* @return @link{CommonDialogWindow}
*/
public CommonDialogWindow getWindow(final E entity, final M metaData) {
public CommonDialogWindow getWindow(final E entity, final String metaDatakey) {
selectedEntity = entity;
final String nameVersion = HawkbitCommonUtil.getFormattedNameVersion(entity.getName(), entity.getVersion());
@@ -150,7 +150,7 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
metadataWindow.setWidth(800, Unit.PIXELS);
metadataWindow.getMainLayout().setSizeFull();
metadataWindow.getButtonsLayout().setHeight("45px");
setUpDetails(entity.getId(), metaData);
setUpDetails(entity.getId(), metaDatakey);
return metadataWindow;
}
@@ -170,13 +170,13 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
protected abstract List<M> getMetadataList();
protected abstract void deleteMetadata(E entity, String key, String value);
protected abstract void deleteMetadata(E entity, String key);
protected abstract boolean hasCreatePermission();
protected abstract boolean hasUpdatePermission();
private void createComponents() {
protected void createComponents() {
keyTextField = createKeyTextField();
valueTextArea = createValueTextField();
metaDataGrid = createMetadataGrid();
@@ -211,13 +211,7 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
tableLayout.addStyleName("table-layout");
tableLayout.setExpandRatio(metaDataGrid, 1.0F);
final VerticalLayout metadataFieldsLayout = new VerticalLayout();
metadataFieldsLayout.setSizeFull();
metadataFieldsLayout.setHeight("100%");
metadataFieldsLayout.addComponent(keyTextField);
metadataFieldsLayout.addComponent(valueTextArea);
metadataFieldsLayout.setSpacing(true);
metadataFieldsLayout.setExpandRatio(valueTextArea, 1F);
final VerticalLayout metadataFieldsLayout = createMetadataFieldsLayout();
mainLayout = new HorizontalLayout();
mainLayout.addComponent(tableLayout);
@@ -230,6 +224,17 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
setSizeFull();
}
protected VerticalLayout createMetadataFieldsLayout() {
final VerticalLayout metadataFieldsLayout = new VerticalLayout();
metadataFieldsLayout.setSizeFull();
metadataFieldsLayout.setHeight("100%");
metadataFieldsLayout.addComponent(keyTextField);
metadataFieldsLayout.addComponent(valueTextArea);
metadataFieldsLayout.setSpacing(true);
metadataFieldsLayout.setExpandRatio(valueTextArea, 1F);
return metadataFieldsLayout;
}
private TextField createKeyTextField() {
final TextField keyField = new TextFieldBuilder().caption(i18n.getMessage("textfield.key")).required(true)
.prompt(i18n.getMessage("textfield.key")).immediate(true)
@@ -252,7 +257,7 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
return valueTextArea;
}
private Grid createMetadataGrid() {
protected Grid createMetadataGrid() {
final Grid metadataGrid = new Grid();
metadataGrid.addStyleName(SPUIStyleDefinitions.METADATA_GRID);
metadataGrid.setImmediate(true);
@@ -276,22 +281,21 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
private void onDelete(final RendererClickEvent event) {
final Item item = metaDataGrid.getContainerDataSource().getItem(event.getItemId());
final String key = (String) item.getItemProperty(KEY).getValue();
final String value = (String) item.getItemProperty(VALUE).getValue();
final ConfirmationDialog confirmDialog = new ConfirmationDialog(
i18n.getMessage("caption.metadata.delete.action.confirmbox"),
i18n.getMessage("message.confirm.delete.metadata", key), i18n.getMessage("button.ok"),
i18n.getMessage("button.cancel"), ok -> {
if (ok) {
handleOkDeleteMetadata(event, key, value);
handleOkDeleteMetadata(event, key);
}
});
UI.getCurrent().addWindow(confirmDialog.getWindow());
confirmDialog.getWindow().bringToFront();
}
private void handleOkDeleteMetadata(final RendererClickEvent event, final String key, final String value) {
deleteMetadata(getSelectedEntity(), key, value);
private void handleOkDeleteMetadata(final RendererClickEvent event, final String key) {
deleteMetadata(getSelectedEntity(), key);
uiNotification.displaySuccess(i18n.getMessage("message.metadata.deleted.successfully", key));
final Object selectedRow = metaDataGrid.getSelectedRow();
metaDataGrid.getContainerDataSource().removeItem(event.getItemId());
@@ -306,17 +310,15 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
}
}
} else {
clearTextFields();
resetFields();
}
}
private void clearTextFields() {
keyTextField.clear();
valueTextArea.clear();
private void resetFields() {
clearFields();
metaDataGrid.select(null);
if (hasCreatePermission()) {
keyTextField.setEnabled(true);
valueTextArea.setEnabled(true);
enableEditing();
addIcon.setEnabled(false);
}
}
@@ -341,7 +343,7 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
return swcontactContainer;
}
private void popualateKeyValue(final Object metadataCompositeKey) {
protected Item popualateKeyValue(final Object metadataCompositeKey) {
if (metadataCompositeKey != null) {
final Item item = metaDataGrid.getContainerDataSource().getItem(metadataCompositeKey);
keyTextField.setValue((String) item.getItemProperty(KEY).getValue());
@@ -350,39 +352,47 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
if (hasUpdatePermission()) {
valueTextArea.setEnabled(true);
}
return item;
}
return null;
}
private void populateGrid() {
final List<M> metadataList = getMetadataList();
for (final M metaData : metadataList) {
addItemToGrid(metaData.getKey(), metaData.getValue());
addItemToGrid(metaData);
}
}
private void addItemToGrid(final String key, final String value) {
protected Item addItemToGrid(final M metaData) {
final IndexedContainer metadataContainer = (IndexedContainer) metaDataGrid.getContainerDataSource();
final Item item = metadataContainer.addItem(key);
item.getItemProperty(VALUE).setValue(value);
item.getItemProperty(KEY).setValue(key);
final Item item = metadataContainer.addItem(metaData.getKey());
item.getItemProperty(VALUE).setValue(metaData.getValue());
item.getItemProperty(KEY).setValue(metaData.getKey());
return item;
}
private void updateItemInGrid(final String key) {
protected Item updateItemInGrid(final String key) {
final IndexedContainer metadataContainer = (IndexedContainer) metaDataGrid.getContainerDataSource();
final Item item = metadataContainer.getItem(key);
item.getItemProperty(VALUE).setValue(valueTextArea.getValue());
return item;
}
private void onAdd() {
metaDataGrid.deselect(metaDataGrid.getSelectedRow());
valueTextArea.clear();
keyTextField.clear();
keyTextField.setEnabled(true);
valueTextArea.setEnabled(true);
clearFields();
enableEditing();
addIcon.setEnabled(true);
}
private void onSave() {
protected void clearFields() {
valueTextArea.clear();
keyTextField.clear();
}
protected void onSave() {
final String key = keyTextField.getValue();
final String value = valueTextArea.getValue();
if (mandatoryCheck()) {
@@ -391,7 +401,7 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
if (!duplicateCheck(entity)) {
final M metadata = createMetadata(entity, key, value);
uiNotification.displaySuccess(i18n.getMessage("message.metadata.saved", metadata.getKey()));
addItemToGrid(metadata.getKey(), metadata.getValue());
addItemToGrid(metadata);
metaDataGrid.scrollToEnd();
metaDataGrid.select(metadata.getKey());
addIcon.setEnabled(true);
@@ -456,17 +466,15 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
}
}
private void onRowClick(final SelectionEvent event) {
protected void onRowClick(final SelectionEvent event) {
final Set<Object> itemsSelected = event.getSelected();
if (!itemsSelected.isEmpty()) {
popualateKeyValue(itemsSelected.iterator().next());
addIcon.setEnabled(true);
} else {
keyTextField.clear();
valueTextArea.clear();
clearFields();
if (hasCreatePermission()) {
keyTextField.setEnabled(true);
valueTextArea.setEnabled(true);
enableEditing();
addIcon.setEnabled(false);
} else {
keyTextField.setEnabled(false);
@@ -476,6 +484,11 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
metadataWindow.setSaveButtonEnabled(false);
}
protected void enableEditing() {
keyTextField.setEnabled(true);
valueTextArea.setEnabled(true);
}
private void onValueChange(final TextChangeEvent event) {
if (hasCreatePermission() || hasUpdatePermission()) {
if (!keyTextField.getValue().isEmpty() && !event.getText().isEmpty()) {
@@ -486,33 +499,47 @@ public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity
}
}
private void setUpDetails(final Long swId, final M metaData) {
private void setUpDetails(final Long swId, final String metaDatakey) {
resetDetails();
if (swId != null) {
metaDataGrid.getContainerDataSource().removeAllItems();
populateGrid();
metaDataGrid.getSelectionModel().reset();
if (!metaDataGrid.getContainerDataSource().getItemIds().isEmpty()) {
if (metaData == null) {
if (metaDatakey == null) {
metaDataGrid.select(metaDataGrid.getContainerDataSource().getIdByIndex(0));
} else {
metaDataGrid.select(metaData.getKey());
metaDataGrid.select(metaDatakey);
}
} else if (hasCreatePermission()) {
keyTextField.setEnabled(true);
valueTextArea.setEnabled(true);
enableEditing();
addIcon.setEnabled(false);
}
}
}
private void resetDetails() {
keyTextField.clear();
valueTextArea.clear();
keyTextField.setEnabled(false);
valueTextArea.setEnabled(false);
clearFields();
disableEditing();
metadataWindow.setSaveButtonEnabled(false);
addIcon.setEnabled(true);
}
protected void disableEditing() {
keyTextField.setEnabled(false);
valueTextArea.setEnabled(false);
}
protected TextArea getValueTextArea() {
return valueTextArea;
}
protected TextField getKeyTextField() {
return keyTextField;
}
protected CommonDialogWindow getMetadataWindow() {
return metadataWindow;
}
}

View File

@@ -12,7 +12,6 @@ import java.util.Optional;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.common.tagdetails.DistributionTagToken;
@@ -45,7 +44,7 @@ public abstract class AbstractDistributionSetDetails
private final DistributionAddUpdateWindowLayout distributionAddUpdateWindowLayout;
private final DistributionSetMetadatadetailsLayout dsMetadataTable;
private final DistributionSetMetadataDetailsLayout dsMetadataTable;
private final UINotification uiNotification;
@@ -63,8 +62,8 @@ public abstract class AbstractDistributionSetDetails
final SpPermissionChecker permissionChecker, final ManagementUIState managementUIState,
final DistributionAddUpdateWindowLayout distributionAddUpdateWindowLayout,
final DistributionSetManagement distributionSetManagement,
final DsMetadataPopupLayout dsMetadataPopupLayout, final EntityFactory entityFactory,
final UINotification uiNotification, final DistributionSetTagManagement distributionSetTagManagement,
final DsMetadataPopupLayout dsMetadataPopupLayout, final UINotification uiNotification,
final DistributionSetTagManagement distributionSetTagManagement,
final SoftwareModuleDetailsTable softwareModuleDetailsTable) {
super(i18n, eventBus, permissionChecker, managementUIState);
this.distributionAddUpdateWindowLayout = distributionAddUpdateWindowLayout;
@@ -75,8 +74,8 @@ public abstract class AbstractDistributionSetDetails
managementUIState, distributionSetTagManagement, distributionSetManagement);
this.softwareModuleDetailsTable = softwareModuleDetailsTable;
dsMetadataTable = new DistributionSetMetadatadetailsLayout(i18n, permissionChecker, distributionSetManagement,
dsMetadataPopupLayout, entityFactory, uiNotification);
dsMetadataTable = new DistributionSetMetadataDetailsLayout(i18n, distributionSetManagement,
dsMetadataPopupLayout);
createSoftwareModuleTab();
addDetailsTab();
}
@@ -106,7 +105,7 @@ public abstract class AbstractDistributionSetDetails
@Override
protected boolean hasEditPermission() {
return getPermissionChecker().hasUpdateDistributionPermission();
return getPermissionChecker().hasUpdateRepositoryPermission();
}
@Override
@@ -131,8 +130,7 @@ public abstract class AbstractDistributionSetDetails
@Override
protected void showMetadata(final ClickEvent event) {
final Optional<DistributionSet> ds = distributionSetManagement
.get(getSelectedBaseEntityId());
final Optional<DistributionSet> ds = distributionSetManagement.get(getSelectedBaseEntityId());
if (!ds.isPresent()) {
uiNotification.displayWarning(getI18n().getMessage("distributionset.not.exists"));
return;

View File

@@ -0,0 +1,95 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.common.detailslayout;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.data.Item;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.ui.Button;
import com.vaadin.ui.Table;
import com.vaadin.ui.themes.ValoTheme;
/**
* Abstract metadata tab for entities.
*
*/
public abstract class AbstractMetadataDetailsLayout extends Table {
protected static final String METADATA_KEY = "Key";
protected static final int MAX_METADATA_QUERY = 500;
private final VaadinMessageSource i18n;
protected AbstractMetadataDetailsLayout(final VaadinMessageSource i18n) {
this.i18n = i18n;
createMetadataTable();
addCustomGeneratedColumns();
}
private VaadinMessageSource getI18n() {
return i18n;
}
private void createMetadataTable() {
addStyleName(ValoTheme.TABLE_NO_HORIZONTAL_LINES);
addStyleName(ValoTheme.TABLE_NO_STRIPES);
setSelectable(false);
setImmediate(true);
setContainerDataSource(getContainer());
setColumnHeaderMode(ColumnHeaderMode.EXPLICIT);
addTableHeader();
setSizeFull();
// same as height of other tabs in details tabsheet
setHeight(116, Unit.PIXELS);
}
private IndexedContainer getContainer() {
final IndexedContainer container = new IndexedContainer();
container.addContainerProperty(METADATA_KEY, String.class, "");
setColumnExpandRatio(METADATA_KEY, 0.7F);
setColumnAlignment(METADATA_KEY, Align.LEFT);
return container;
}
private void addTableHeader() {
setColumnHeader(METADATA_KEY, getI18n().getMessage("header.key"));
}
protected void setMetadataProperties(final MetaData dsMetadata) {
final Item item = getContainerDataSource().addItem(dsMetadata.getKey());
item.getItemProperty(METADATA_KEY).setValue(dsMetadata.getKey());
}
private void addCustomGeneratedColumns() {
addGeneratedColumn(METADATA_KEY, (source, itemId, columnId) -> customMetadataDetailButton((String) itemId));
}
private Button customMetadataDetailButton(final String metadataKey) {
final Button viewIcon = SPUIComponentProvider.getButton(getDetailLinkId(metadataKey), metadataKey,
"View " + metadataKey + " Metadata details", null, false, null, SPUIButtonStyleSmallNoBorder.class);
viewIcon.setData(metadataKey);
viewIcon.addStyleName(ValoTheme.BUTTON_TINY + " " + ValoTheme.BUTTON_LINK + " " + "on-focus-no-border link"
+ " " + "text-style");
viewIcon.addClickListener(event -> showMetadataDetails(metadataKey));
return viewIcon;
}
protected abstract String getDetailLinkId(final String name);
protected abstract void showMetadataDetails(final String metadataKey);
}

View File

@@ -8,15 +8,12 @@
*/
package org.eclipse.hawkbit.ui.common.detailslayout;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent;
import org.eclipse.hawkbit.ui.artifacts.smtable.SoftwareModuleAddUpdateWindow;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent;
import org.eclipse.hawkbit.ui.distributions.smtable.SwMetadataPopupLayout;
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
@@ -41,7 +38,7 @@ public abstract class AbstractSoftwareModuleDetails
private static final long serialVersionUID = 1L;
private final SoftwareModuleMetadatadetailslayout swmMetadataTable;
private final SoftwareModuleMetadataDetailsLayout swmMetadataTable;
private final SoftwareModuleAddUpdateWindow softwareModuleAddUpdateWindow;
@@ -52,40 +49,18 @@ public abstract class AbstractSoftwareModuleDetails
protected AbstractSoftwareModuleDetails(final VaadinMessageSource i18n, final UIEventBus eventBus,
final SpPermissionChecker permissionChecker, final ManagementUIState managementUIState,
final SoftwareModuleManagement softwareManagement, final SwMetadataPopupLayout swMetadataPopupLayout,
final EntityFactory entityFactory, final SoftwareModuleAddUpdateWindow softwareModuleAddUpdateWindow) {
final SoftwareModuleAddUpdateWindow softwareModuleAddUpdateWindow) {
super(i18n, eventBus, permissionChecker, managementUIState);
this.softwareModuleAddUpdateWindow = softwareModuleAddUpdateWindow;
this.softwareModuleManagement = softwareManagement;
this.swMetadataPopupLayout = swMetadataPopupLayout;
swmMetadataTable = new SoftwareModuleMetadatadetailslayout();
swmMetadataTable.init(getI18n(), getPermissionChecker(), softwareManagement, swMetadataPopupLayout,
entityFactory);
swmMetadataTable = new SoftwareModuleMetadataDetailsLayout(getI18n(), softwareManagement,
swMetadataPopupLayout);
addDetailsTab();
}
/**
* MetadataEvent.
*
* @param event
* as instance of {@link MetadataEvent}
*/
@EventBusListenerMethod(scope = EventScope.UI)
void onEvent(final MetadataEvent event) {
UI.getCurrent().access(() -> {
final MetaData softwareModuleMetadata = event.getMetaData();
if (softwareModuleMetadata == null || !isSoftwareModuleSelected(event.getModule())) {
return;
}
if (event.getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.CREATE_SOFTWARE_MODULE_METADATA) {
swmMetadataTable.createMetadata(event.getMetaData().getKey());
} else if (event.getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.DELETE_SOFTWARE_MODULE_METADATA) {
swmMetadataTable.deleteMetadata(event.getMetaData().getKey());
}
});
}
@EventBusListenerMethod(scope = EventScope.UI)
void onEvent(final SoftwareModuleEvent softwareModuleEvent) {
onBaseEntityEvent(softwareModuleEvent);
@@ -124,7 +99,7 @@ public abstract class AbstractSoftwareModuleDetails
@Override
protected boolean hasEditPermission() {
return getPermissionChecker().hasUpdateDistributionPermission();
return getPermissionChecker().hasUpdateRepositoryPermission();
}
@Override

View File

@@ -0,0 +1,87 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.common.detailslayout;
import java.util.List;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.ui.distributions.dstable.DsMetadataPopupLayout;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.data.domain.PageRequest;
import com.vaadin.ui.UI;
/**
* DistributionSet Metadata details layout.
*
*/
public class DistributionSetMetadataDetailsLayout extends AbstractMetadataDetailsLayout {
private static final long serialVersionUID = 1L;
private final transient DistributionSetManagement distributionSetManagement;
private final DsMetadataPopupLayout dsMetadataPopupLayout;
private Long selectedDistSetId;
/**
* Initialize the layout.
*
* @param i18n
* the i18n service
* @param distributionSetManagement
* the distribution set management service
* @param dsMetadataPopupLayout
* the distribution set metadata popup layout
*/
public DistributionSetMetadataDetailsLayout(final VaadinMessageSource i18n,
final DistributionSetManagement distributionSetManagement,
final DsMetadataPopupLayout dsMetadataPopupLayout) {
super(i18n);
this.distributionSetManagement = distributionSetManagement;
this.dsMetadataPopupLayout = dsMetadataPopupLayout;
}
/**
* Populate software module metadata.
*
* @param distributionSet
*/
public void populateDSMetadata(final DistributionSet distributionSet) {
removeAllItems();
if (null == distributionSet) {
return;
}
selectedDistSetId = distributionSet.getId();
final List<DistributionSetMetadata> dsMetadataList = distributionSetManagement
.findMetaDataByDistributionSetId(new PageRequest(0, MAX_METADATA_QUERY), selectedDistSetId)
.getContent();
if (null != dsMetadataList && !dsMetadataList.isEmpty()) {
dsMetadataList.forEach(this::setMetadataProperties);
}
}
@Override
protected void showMetadataDetails(final String metadataKey) {
distributionSetManagement.get(selectedDistSetId)
.ifPresent(distSet -> UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(distSet, metadataKey)));
}
@Override
protected String getDetailLinkId(final String name) {
return new StringBuilder(UIComponentIdProvider.DS_METADATA_DETAIL_LINK).append('.').append(name).toString();
}
}

View File

@@ -1,165 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.common.detailslayout;
import java.util.List;
import java.util.Optional;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder;
import org.eclipse.hawkbit.ui.distributions.dstable.DsMetadataPopupLayout;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.data.domain.PageRequest;
import com.vaadin.data.Item;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.ui.Button;
import com.vaadin.ui.Label;
import com.vaadin.ui.Table;
import com.vaadin.ui.UI;
import com.vaadin.ui.themes.ValoTheme;
/**
* DistributionSet Metadata details layout.
*
*/
public class DistributionSetMetadatadetailsLayout extends Table {
private static final long serialVersionUID = 2913758299611837718L;
private static final String METADATA_KEY = "Key";
private static final String VIEW = "view";
private final transient DistributionSetManagement distributionSetManagement;
private final DsMetadataPopupLayout dsMetadataPopupLayout;
private final SpPermissionChecker permissionChecker;
private final transient EntityFactory entityFactory;
private final VaadinMessageSource i18n;
private Long selectedDistSetId;
private final UINotification notification;
public DistributionSetMetadatadetailsLayout(final VaadinMessageSource i18n,
final SpPermissionChecker permissionChecker, final DistributionSetManagement distributionSetManagement,
final DsMetadataPopupLayout dsMetadataPopupLayout, final EntityFactory entityFactory,
final UINotification notification) {
this.i18n = i18n;
this.permissionChecker = permissionChecker;
this.distributionSetManagement = distributionSetManagement;
this.dsMetadataPopupLayout = dsMetadataPopupLayout;
this.entityFactory = entityFactory;
this.notification = notification;
createDSMetadataTable();
addCustomGeneratedColumns();
}
/**
* Populate software module metadata.
*
* @param distributionSet
*/
public void populateDSMetadata(final DistributionSet distributionSet) {
removeAllItems();
if (null == distributionSet) {
return;
}
selectedDistSetId = distributionSet.getId();
final List<DistributionSetMetadata> dsMetadataList = distributionSetManagement
.findMetaDataByDistributionSetId(new PageRequest(0, 500), selectedDistSetId)
.getContent();
if (null != dsMetadataList && !dsMetadataList.isEmpty()) {
dsMetadataList.forEach(dsMetadata -> setDSMetadataProperties(dsMetadata));
}
}
private void createDSMetadataTable() {
addStyleName(ValoTheme.TABLE_NO_HORIZONTAL_LINES);
addStyleName(ValoTheme.TABLE_NO_STRIPES);
addStyleName(SPUIStyleDefinitions.SW_MODULE_TABLE);
addStyleName("details-layout");
setSelectable(false);
setImmediate(true);
setContainerDataSource(getDistSetContainer());
setColumnHeaderMode(ColumnHeaderMode.EXPLICIT);
addDSMetadataTableHeader();
setSizeFull();
// same as height of other tabs in details tabsheet
setHeight(116, Unit.PIXELS);
}
private IndexedContainer getDistSetContainer() {
final IndexedContainer container = new IndexedContainer();
container.addContainerProperty(METADATA_KEY, String.class, "");
setColumnExpandRatio(METADATA_KEY, 0.7F);
setColumnAlignment(METADATA_KEY, Align.LEFT);
if (permissionChecker.hasUpdateDistributionPermission()) {
container.addContainerProperty(VIEW, Label.class, "");
setColumnExpandRatio(VIEW, 0.2F);
setColumnAlignment(VIEW, Align.RIGHT);
}
return container;
}
private void addDSMetadataTableHeader() {
setColumnHeader(METADATA_KEY, i18n.getMessage("header.key"));
}
private void setDSMetadataProperties(final DistributionSetMetadata dsMetadata) {
final Item item = getContainerDataSource().addItem(dsMetadata.getKey());
item.getItemProperty(METADATA_KEY).setValue(dsMetadata.getKey());
}
private void addCustomGeneratedColumns() {
addGeneratedColumn(METADATA_KEY, (source, itemId, columnId) -> customMetadataDetailButton((String) itemId));
}
private Button customMetadataDetailButton(final String metadataKey) {
final Button viewIcon = SPUIComponentProvider.getButton(getDetailLinkId(metadataKey), metadataKey,
"View " + metadataKey + " Metadata details", null, false, null, SPUIButtonStyleSmallNoBorder.class);
viewIcon.setData(metadataKey);
viewIcon.addStyleName(ValoTheme.BUTTON_TINY + " " + ValoTheme.BUTTON_LINK + " " + "on-focus-no-border link"
+ " " + "text-style");
viewIcon.addClickListener(event -> showMetadataDetails(selectedDistSetId, metadataKey));
return viewIcon;
}
private static String getDetailLinkId(final String name) {
return new StringBuilder(UIComponentIdProvider.DS_METADATA_DETAIL_LINK).append('.').append(name).toString();
}
private void showMetadataDetails(final Long selectedDistSetId, final String metadataKey) {
final Optional<DistributionSet> distSet = distributionSetManagement.get(selectedDistSetId);
if (!distSet.isPresent()) {
notification.displayWarning(i18n.getMessage("distributionset.not.exists"));
return;
}
/* display the window */
UI.getCurrent().addWindow(
dsMetadataPopupLayout.getWindow(distSet.get(), entityFactory.generateMetadata(metadataKey, "")));
}
}

View File

@@ -145,7 +145,7 @@ public class SoftwareModuleDetailsTable extends Table {
public void populateModule(final DistributionSet distributionSet) {
removeAllItems();
if (distributionSet != null) {
if (isUnassignSoftModAllowed && permissionChecker.hasUpdateDistributionPermission()) {
if (isUnassignSoftModAllowed && permissionChecker.hasUpdateRepositoryPermission()) {
try {
isTargetAssigned = false;
} catch (final EntityReadOnlyException exception) {
@@ -229,7 +229,7 @@ public class SoftwareModuleDetailsTable extends Table {
softwareModule.setId(sw.getName() + "-label");
horizontalLayout.addComponent(softwareModule);
horizontalLayout.setExpandRatio(softwareModule, 1F);
if (isUnassignSoftModAllowed && permissionChecker.hasUpdateDistributionPermission() && !isTargetAssigned
if (isUnassignSoftModAllowed && permissionChecker.hasUpdateRepositoryPermission() && !isTargetAssigned
&& (isSoftModAvaiableForSoftType(alreadyAssignedSwModules, swModType))) {
horizontalLayout.addComponent(reassignSoftModule);
}

View File

@@ -0,0 +1,85 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.common.detailslayout;
import java.util.List;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.ui.distributions.smtable.SwMetadataPopupLayout;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.data.domain.PageRequest;
import org.springframework.util.CollectionUtils;
import com.vaadin.ui.UI;
/**
* SoftwareModule Metadata details layout.
*
*/
public class SoftwareModuleMetadataDetailsLayout extends AbstractMetadataDetailsLayout {
private static final long serialVersionUID = 1L;
private transient SoftwareModuleManagement softwareModuleManagement;
private final SwMetadataPopupLayout swMetadataPopupLayout;
private Long selectedSWModuleId;
/**
* Initialize the layout.
*
* @param i18n
* the i18n service
* @param softwareManagement
* the software management service
* @param swMetadataPopupLayout
* the software module metadata popup layout
*/
public SoftwareModuleMetadataDetailsLayout(final VaadinMessageSource i18n,
final SoftwareModuleManagement softwareManagement, final SwMetadataPopupLayout swMetadataPopupLayout) {
super(i18n);
this.softwareModuleManagement = softwareManagement;
this.swMetadataPopupLayout = swMetadataPopupLayout;
}
/**
* Populate software module metadata table.
*
* @param swModule
*/
public void populateSMMetadata(final SoftwareModule swModule) {
removeAllItems();
if (null == swModule) {
return;
}
selectedSWModuleId = swModule.getId();
final List<SoftwareModuleMetadata> swMetadataList = softwareModuleManagement
.findMetaDataBySoftwareModuleId(new PageRequest(0, MAX_METADATA_QUERY), selectedSWModuleId)
.getContent();
if (!CollectionUtils.isEmpty(swMetadataList)) {
swMetadataList.forEach(this::setMetadataProperties);
}
}
@Override
protected void showMetadataDetails(final String metadataKey) {
softwareModuleManagement.get(selectedSWModuleId).ifPresent(
swmodule -> UI.getCurrent().addWindow(swMetadataPopupLayout.getWindow(swmodule, metadataKey)));
}
@Override
protected String getDetailLinkId(final String name) {
return new StringBuilder(UIComponentIdProvider.SW_METADATA_DETAIL_LINK).append('.').append(name).toString();
}
}

View File

@@ -1,185 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.common.detailslayout;
import java.util.List;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder;
import org.eclipse.hawkbit.ui.distributions.smtable.SwMetadataPopupLayout;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.data.domain.PageRequest;
import org.springframework.util.CollectionUtils;
import com.vaadin.data.Item;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.spring.annotation.UIScope;
import com.vaadin.ui.Button;
import com.vaadin.ui.Table;
import com.vaadin.ui.UI;
import com.vaadin.ui.themes.ValoTheme;
/**
* SoftwareModule Metadata details layout.
*
*/
@SpringComponent
@UIScope
public class SoftwareModuleMetadatadetailslayout extends Table {
private static final long serialVersionUID = 2913758299611838818L;
private static final String METADATA_KEY = "Key";
private static final int MAX_METADATA_QUERY = 500;
private SpPermissionChecker permissionChecker;
private transient SoftwareModuleManagement softwareModuleManagement;
private SwMetadataPopupLayout swMetadataPopupLayout;
private VaadinMessageSource i18n;
private Long selectedSWModuleId;
private transient EntityFactory entityFactory;
/**
* Initialize the layout.
*
* @param i18n
* the i18n service
* @param permissionChecker
* the permission checker service
* @param softwareManagement
* the software management service
* @param swMetadataPopupLayout
* the software module metadata popup layout
* @param entityFactory
* the entity factory service
*/
public void init(final VaadinMessageSource i18n, final SpPermissionChecker permissionChecker,
final SoftwareModuleManagement softwareManagement, final SwMetadataPopupLayout swMetadataPopupLayout,
final EntityFactory entityFactory) {
this.i18n = i18n;
this.permissionChecker = permissionChecker;
this.softwareModuleManagement = softwareManagement;
this.swMetadataPopupLayout = swMetadataPopupLayout;
this.entityFactory = entityFactory;
createSWMMetadataTable();
addCustomGeneratedColumns();
}
/**
* Populate software module metadata table.
*
* @param swModule
*/
public void populateSMMetadata(final SoftwareModule swModule) {
removeAllItems();
if (null == swModule) {
return;
}
selectedSWModuleId = swModule.getId();
final List<SoftwareModuleMetadata> swMetadataList = softwareModuleManagement
.findMetaDataBySoftwareModuleId(new PageRequest(0, MAX_METADATA_QUERY),
selectedSWModuleId)
.getContent();
if (!CollectionUtils.isEmpty(swMetadataList)) {
swMetadataList.forEach(this::setSWMetadataProperties);
}
}
/**
* Create metadata.
*
* @param metadataKeyName
*/
public void createMetadata(final String metadataKeyName) {
final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource();
final Item item = metadataContainer.addItem(metadataKeyName);
item.getItemProperty(METADATA_KEY).setValue(metadataKeyName);
}
/**
* Delete metadata.
*
* @param metadataKeyName
*/
public void deleteMetadata(final String metadataKeyName) {
final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource();
metadataContainer.removeItem(metadataKeyName);
}
private void createSWMMetadataTable() {
addStyleName(ValoTheme.TABLE_NO_HORIZONTAL_LINES);
addStyleName(ValoTheme.TABLE_NO_STRIPES);
addStyleName(SPUIStyleDefinitions.SW_MODULE_TABLE);
setSelectable(false);
setImmediate(true);
setContainerDataSource(getSwModuleMetadataContainer());
setColumnHeaderMode(ColumnHeaderMode.EXPLICIT);
addSMMetadataTableHeader();
setSizeFull();
// same as height of other tabs in details tabsheet
setHeight(116, Unit.PIXELS);
}
private IndexedContainer getSwModuleMetadataContainer() {
final IndexedContainer container = new IndexedContainer();
container.addContainerProperty(METADATA_KEY, String.class, "");
setColumnAlignment(METADATA_KEY, Align.LEFT);
return container;
}
private void addSMMetadataTableHeader() {
setColumnHeader(METADATA_KEY, i18n.getMessage("header.key"));
}
private void setSWMetadataProperties(final SoftwareModuleMetadata swMetadata) {
final Item item = getContainerDataSource().addItem(swMetadata.getKey());
item.getItemProperty(METADATA_KEY).setValue(swMetadata.getKey());
}
private void addCustomGeneratedColumns() {
addGeneratedColumn(METADATA_KEY, (source, itemId, columnId) -> customMetadataDetailButton((String) itemId));
}
private Button customMetadataDetailButton(final String metadataKey) {
final Button viewLink = SPUIComponentProvider.getButton(getDetailLinkId(metadataKey), metadataKey,
"View" + metadataKey + " Metadata details", null, false, null, SPUIButtonStyleSmallNoBorder.class);
viewLink.setData(metadataKey);
if (permissionChecker.hasUpdateDistributionPermission()) {
viewLink.addStyleName(ValoTheme.BUTTON_TINY + " " + ValoTheme.BUTTON_LINK + " " + "on-focus-no-border link"
+ " " + "text-style");
viewLink.addClickListener(event -> showMetadataDetails(selectedSWModuleId, metadataKey));
}
return viewLink;
}
private static String getDetailLinkId(final String name) {
return new StringBuilder(UIComponentIdProvider.SW_METADATA_DETAIL_LINK).append('.').append(name).toString();
}
private void showMetadataDetails(final Long selectedSWModuleId, final String metadataKey) {
softwareModuleManagement.get(selectedSWModuleId).ifPresent(swmodule -> UI.getCurrent()
.addWindow(swMetadataPopupLayout.getWindow(swmodule, entityFactory.generateMetadata(metadataKey, ""))));
}
}

View File

@@ -61,7 +61,7 @@ public abstract class AbstractDistributionSetTableHeader extends AbstractTableHe
@Override
protected boolean hasCreatePermission() {
return permChecker.hasCreateDistributionPermission();
return permChecker.hasCreateRepositoryPermission();
}
@Override

View File

@@ -86,7 +86,7 @@ public abstract class AbstractSoftwareModuleTableHeader extends AbstractTableHea
@Override
protected boolean hasCreatePermission() {
return permChecker.hasCreateDistributionPermission();
return permChecker.hasCreateRepositoryPermission();
}
@Override

View File

@@ -101,7 +101,7 @@ public class DistributionTagToken extends AbstractTagToken<DistributionSet> {
@Override
protected Boolean isToggleTagAssignmentAllowed() {
return checker.hasUpdateDistributionPermission();
return checker.hasUpdateRepositoryPermission();
}
@Override

View File

@@ -172,8 +172,8 @@ public class DistributionsView extends AbstractNotificationView implements Brows
}
private boolean hasUserPermission() {
return permChecker.hasUpdateDistributionPermission() || permChecker.hasCreateDistributionPermission()
|| permChecker.hasReadDistributionPermission();
return permChecker.hasUpdateRepositoryPermission() || permChecker.hasCreateRepositoryPermission()
|| permChecker.hasReadRepositoryPermission();
}
private void createMainLayout() {

View File

@@ -54,7 +54,7 @@ public class DSTypeFilterHeader extends AbstractFilterHeader {
@Override
protected boolean hasCreateUpdatePermission() {
return permChecker.hasCreateDistributionPermission() || permChecker.hasUpdateDistributionPermission();
return permChecker.hasCreateRepositoryPermission() || permChecker.hasUpdateRepositoryPermission();
}
@Override

View File

@@ -14,7 +14,6 @@ import java.util.Set;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
@@ -71,13 +70,12 @@ public class DistributionSetDetails extends AbstractDistributionSetDetails {
final DistributionAddUpdateWindowLayout distributionAddUpdateWindowLayout,
final SoftwareModuleManagement softwareManagement,
final DistributionSetManagement distributionSetManagement, final TargetManagement targetManagement,
final EntityFactory entityFactory, final UINotification uiNotification,
final DistributionSetTagManagement distributionSetTagManagement,
final UINotification uiNotification, final DistributionSetTagManagement distributionSetTagManagement,
final DsMetadataPopupLayout dsMetadataPopupLayout) {
super(i18n, eventBus, permissionChecker, managementUIState, distributionAddUpdateWindowLayout,
distributionSetManagement, dsMetadataPopupLayout, entityFactory, uiNotification,
distributionSetTagManagement, createSoftwareModuleDetailsTable(i18n, permissionChecker,
distributionSetManagement, eventBus, manageDistUIState, uiNotification));
distributionSetManagement, dsMetadataPopupLayout, uiNotification, distributionSetTagManagement,
createSoftwareModuleDetailsTable(i18n, permissionChecker, distributionSetManagement, eventBus,
manageDistUIState, uiNotification));
this.manageDistUIState = manageDistUIState;
this.softwareModuleManagement = softwareManagement;
this.targetManagement = targetManagement;
@@ -127,8 +125,7 @@ public class DistributionSetDetails extends AbstractDistributionSetDetails {
assignedSWModule = new HashMap<>();
}
softwareModuleIdNameList.stream().map(SoftwareModuleIdName::getId)
.map(softwareModuleManagement::get)
softwareModuleIdNameList.stream().map(SoftwareModuleIdName::getId).map(softwareModuleManagement::get)
.forEach(found -> found.ifPresent(softwareModule -> {
if (assignedSWModule.containsKey(softwareModule.getType().getName())) {
@@ -157,7 +154,7 @@ public class DistributionSetDetails extends AbstractDistributionSetDetails {
}
private Button assignSoftModuleButton(final String softwareModuleName) {
if (getPermissionChecker().hasUpdateDistributionPermission() && manageDistUIState.getLastSelectedDistribution()
if (getPermissionChecker().hasUpdateRepositoryPermission() && manageDistUIState.getLastSelectedDistribution()
.map(selected -> targetManagement.countByAssignedDistributionSet(selected) <= 0).orElse(false)) {
final Button reassignSoftModule = SPUIComponentProvider.getButton(softwareModuleName, "", "", "", true,
@@ -255,11 +252,10 @@ public class DistributionSetDetails extends AbstractDistributionSetDetails {
assignedSWModule.clear();
}
getDistributionSetManagement().getWithDetails(getSelectedBaseEntityId())
.ifPresent(set -> {
setSelectedBaseEntity(set);
UI.getCurrent().access(this::populateModule);
});
getDistributionSetManagement().getWithDetails(getSelectedBaseEntityId()).ifPresent(set -> {
setSelectedBaseEntity(set);
UI.getCurrent().access(this::populateModule);
});
}
}

View File

@@ -385,7 +385,7 @@ public class DistributionSetTable extends AbstractNamedVersionTable<Distribution
@Override
protected boolean hasDropPermission() {
return permissionChecker.hasUpdateDistributionPermission();
return permissionChecker.hasUpdateRepositoryPermission();
}
private void addTableStyleGenerator() {

View File

@@ -60,7 +60,7 @@ public class DistributionSetTableLayout extends AbstractTableLayout<Distribution
distributionSetTable,
new DistributionSetDetails(i18n, eventBus, permissionChecker, manageDistUIState, null,
distributionAddUpdateWindowLayout, softwareManagement, distributionSetManagement,
targetManagement, entityFactory, uiNotification, distributionSetTagManagement, popupLayout));
targetManagement, uiNotification, distributionSetTagManagement, popupLayout));
}
public DistributionSetTable getDistributionSetTable() {

View File

@@ -51,8 +51,8 @@ public class DsMetadataPopupLayout extends AbstractMetadataPopupLayout<Distribut
@Override
protected DistributionSetMetadata createMetadata(final DistributionSet entity, final String key,
final String value) {
final DistributionSetMetadata dsMetaData = distributionSetManagement.createMetaData(
entity.getId(), Arrays.asList(entityFactory.generateMetadata(key, value))).get(0);
final DistributionSetMetadata dsMetaData = distributionSetManagement
.createMetaData(entity.getId(), Arrays.asList(entityFactory.generateMetadata(key, value))).get(0);
setSelectedEntity(dsMetaData.getDistributionSet());
return dsMetaData;
}
@@ -60,8 +60,8 @@ public class DsMetadataPopupLayout extends AbstractMetadataPopupLayout<Distribut
@Override
protected DistributionSetMetadata updateMetadata(final DistributionSet entity, final String key,
final String value) {
final DistributionSetMetadata dsMetaData = distributionSetManagement
.updateMetaData(entity.getId(), entityFactory.generateMetadata(key, value));
final DistributionSetMetadata dsMetaData = distributionSetManagement.updateMetaData(entity.getId(),
entityFactory.generateMetadata(key, value));
setSelectedEntity(dsMetaData.getDistributionSet());
return dsMetaData;
}
@@ -69,22 +69,21 @@ public class DsMetadataPopupLayout extends AbstractMetadataPopupLayout<Distribut
@Override
protected List<MetaData> getMetadataList() {
return Collections.unmodifiableList(distributionSetManagement
.findMetaDataByDistributionSetId(new PageRequest(0, 500), getSelectedEntity().getId())
.getContent());
.findMetaDataByDistributionSetId(new PageRequest(0, 500), getSelectedEntity().getId()).getContent());
}
@Override
protected void deleteMetadata(final DistributionSet entity, final String key, final String value) {
protected void deleteMetadata(final DistributionSet entity, final String key) {
distributionSetManagement.deleteMetaData(entity.getId(), key);
}
@Override
protected boolean hasCreatePermission() {
return permChecker.hasCreateDistributionPermission();
return permChecker.hasCreateRepositoryPermission();
}
@Override
protected boolean hasUpdatePermission() {
return permChecker.hasUpdateDistributionPermission();
return permChecker.hasUpdateRepositoryPermission();
}
}

View File

@@ -1,49 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.distributions.event;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
/**
*
* Metadata Events.
*
*/
public class MetadataEvent {
public enum MetadataUIEvent {
DELETE_SOFTWARE_MODULE_METADATA, CREATE_SOFTWARE_MODULE_METADATA;
}
private final MetadataUIEvent metadataUIEvent;
private final MetaData metadata;
private final SoftwareModule module;
public MetadataEvent(final MetadataUIEvent metadataUIEvent, final MetaData metadata, final SoftwareModule module) {
this.metadataUIEvent = metadataUIEvent;
this.metadata = metadata;
this.module = module;
}
public MetadataUIEvent getMetadataUIEvent() {
return metadataUIEvent;
}
public MetaData getMetaData() {
return metadata;
}
public SoftwareModule getModule() {
return module;
}
}

View File

@@ -100,14 +100,14 @@ public class DSDeleteActionsLayout extends AbstractDeleteActionsLayout {
@Override
protected boolean hasDeletePermission() {
return permChecker.hasDeleteDistributionPermission();
return permChecker.hasDeleteRepositoryPermission();
}
@Override
protected boolean hasUpdatePermission() {
return permChecker.hasUpdateDistributionPermission();
return permChecker.hasUpdateRepositoryPermission();
}
@Override

View File

@@ -13,28 +13,35 @@ import java.util.List;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.common.AbstractMetadataPopupLayout;
import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent;
import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent.MetadataUIEvent;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.data.domain.PageRequest;
import org.vaadin.spring.events.EventBus.UIEventBus;
import com.vaadin.data.Item;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Grid;
import com.vaadin.ui.VerticalLayout;
/**
* Pop up layout to display software module metadata.
*/
public class SwMetadataPopupLayout extends AbstractMetadataPopupLayout<SoftwareModule, MetaData> {
public class SwMetadataPopupLayout extends AbstractMetadataPopupLayout<SoftwareModule, SoftwareModuleMetadata> {
private static final long serialVersionUID = -1252090014161012563L;
private static final long serialVersionUID = 1L;
protected static final String TARGET_VISIBLE = "targetVisible";
private final transient SoftwareModuleManagement softwareModuleManagement;
private final transient EntityFactory entityFactory;
private CheckBox targetVisibleField;
public SwMetadataPopupLayout(final VaadinMessageSource i18n, final UINotification uiNotification,
final UIEventBus eventBus, final SoftwareModuleManagement softwareManagement,
@@ -49,52 +56,135 @@ public class SwMetadataPopupLayout extends AbstractMetadataPopupLayout<SoftwareM
return softwareModuleManagement.getMetaDataBySoftwareModuleId(entity.getId(), value).isPresent();
}
/**
* Create metadata for SWModule.
*/
@Override
protected SoftwareModuleMetadata createMetadata(final SoftwareModule entity, final String key, final String value) {
final SoftwareModuleMetadata swMetadata = softwareModuleManagement.createMetaData(entity.getId(),
entityFactory.generateMetadata(key, value));
final SoftwareModuleMetadata swMetadata = softwareModuleManagement
.createMetaData(entityFactory.softwareModuleMetadata().create(entity.getId()).key(key).value(value)
.targetVisible(targetVisibleField.getValue()));
setSelectedEntity(swMetadata.getSoftwareModule());
eventBus.publish(this, new MetadataEvent(MetadataUIEvent.CREATE_SOFTWARE_MODULE_METADATA, swMetadata, entity));
return swMetadata;
}
/**
* Update metadata for SWModule.
*/
@Override
protected SoftwareModuleMetadata updateMetadata(final SoftwareModule entity, final String key, final String value) {
final SoftwareModuleMetadata swMetadata = softwareModuleManagement.updateMetaData(entity.getId(),
entityFactory.generateMetadata(key, value));
final SoftwareModuleMetadata swMetadata = softwareModuleManagement
.updateMetaData(entityFactory.softwareModuleMetadata().update(entity.getId(), key).value(value)
.targetVisible(targetVisibleField.getValue()));
setSelectedEntity(swMetadata.getSoftwareModule());
return swMetadata;
}
@Override
protected List<MetaData> getMetadataList() {
protected List<SoftwareModuleMetadata> getMetadataList() {
return Collections.unmodifiableList(softwareModuleManagement
.findMetaDataBySoftwareModuleId(new PageRequest(0, MAX_METADATA_QUERY), getSelectedEntity().getId()).getContent());
.findMetaDataBySoftwareModuleId(new PageRequest(0, MAX_METADATA_QUERY), getSelectedEntity().getId())
.getContent());
}
/**
* delete metadata for SWModule.
*/
@Override
protected void deleteMetadata(final SoftwareModule entity, final String key, final String value) {
protected Grid createMetadataGrid() {
final Grid metadataGrid = super.createMetadataGrid();
metadataGrid.getContainerDataSource().addContainerProperty(TARGET_VISIBLE, Boolean.class, Boolean.FALSE);
metadataGrid.getColumn(TARGET_VISIBLE).setHeaderCaption(i18n.getMessage("metadata.targetvisible"));
metadataGrid.getColumn(TARGET_VISIBLE).setHidden(true);
return metadataGrid;
}
@Override
protected void deleteMetadata(final SoftwareModule entity, final String key) {
softwareModuleManagement.deleteMetaData(entity.getId(), key);
eventBus.publish(this, new MetadataEvent(MetadataUIEvent.DELETE_SOFTWARE_MODULE_METADATA,
entityFactory.generateMetadata(key, value), entity));
}
@Override
protected boolean hasCreatePermission() {
return permChecker.hasCreateDistributionPermission();
return permChecker.hasCreateRepositoryPermission();
}
@Override
protected boolean hasUpdatePermission() {
return permChecker.hasUpdateDistributionPermission();
return permChecker.hasUpdateRepositoryPermission();
}
private CheckBox createTargetVisibleField() {
final CheckBox checkBox = new CheckBox();
checkBox.setId(UIComponentIdProvider.METADATA_TARGET_VISIBLE_ID);
checkBox.setCaption(i18n.getMessage("metadata.targetvisible"));
checkBox.addValueChangeListener(this::onCheckBoxChange);
return checkBox;
}
// Exception for squid:S1172 - parameter defined by Vaadin
@SuppressWarnings("squid:S1172")
private void onCheckBoxChange(final ValueChangeEvent event) {
if (hasCreatePermission() || hasUpdatePermission()) {
if (!getValueTextArea().getValue().isEmpty() && !getKeyTextField().getValue().isEmpty()) {
getMetadataWindow().setSaveButtonEnabled(true);
} else {
getMetadataWindow().setSaveButtonEnabled(false);
}
}
}
@Override
protected void createComponents() {
super.createComponents();
targetVisibleField = createTargetVisibleField();
}
@Override
protected VerticalLayout createMetadataFieldsLayout() {
final VerticalLayout metadataFieldsLayout = super.createMetadataFieldsLayout();
metadataFieldsLayout.addComponent(targetVisibleField);
return metadataFieldsLayout;
}
@Override
protected Item popualateKeyValue(final Object metadataCompositeKey) {
final Item item = super.popualateKeyValue(metadataCompositeKey);
if (item != null) {
targetVisibleField.setValue((Boolean) item.getItemProperty(TARGET_VISIBLE).getValue());
if (hasUpdatePermission()) {
targetVisibleField.setEnabled(true);
}
}
return item;
}
@Override
protected Item updateItemInGrid(final String key) {
final Item item = super.updateItemInGrid(key);
item.getItemProperty(TARGET_VISIBLE).setValue(targetVisibleField.getValue());
return item;
}
@Override
protected Item addItemToGrid(final SoftwareModuleMetadata metaData) {
final Item item = super.addItemToGrid(metaData);
item.getItemProperty(TARGET_VISIBLE).setValue(metaData.isTargetVisible());
return item;
}
@Override
protected void enableEditing() {
super.enableEditing();
targetVisibleField.setEnabled(true);
}
@Override
protected void clearFields() {
super.clearFields();
targetVisibleField.clear();
}
@Override
protected void disableEditing() {
super.disableEditing();
targetVisibleField.setEnabled(false);
}
}

View File

@@ -8,7 +8,6 @@
*/
package org.eclipse.hawkbit.ui.distributions.smtable;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
@@ -33,8 +32,8 @@ public class SwModuleDetails extends AbstractSoftwareModuleDetails {
final SpPermissionChecker permissionChecker,
final SoftwareModuleAddUpdateWindow softwareModuleAddUpdateWindow,
final ManageDistUIState manageDistUIState, final SoftwareModuleManagement softwareManagement,
final SwMetadataPopupLayout swMetadataPopupLayout, final EntityFactory entityFactory) {
super(i18n, eventBus, permissionChecker, null, softwareManagement, swMetadataPopupLayout, entityFactory,
final SwMetadataPopupLayout swMetadataPopupLayout) {
super(i18n, eventBus, permissionChecker, null, softwareManagement, swMetadataPopupLayout,
softwareModuleAddUpdateWindow);
this.manageDistUIState = manageDistUIState;
restoreState();

View File

@@ -41,8 +41,9 @@ public class SwModuleTableLayout extends AbstractTableLayout<SwModuleTable> {
final SwMetadataPopupLayout swMetadataPopupLayout = new SwMetadataPopupLayout(i18n, uiNotification, eventBus,
softwareModuleManagement, entityFactory, permChecker);
this.swModuleTable = new SwModuleTable(eventBus, i18n, uiNotification, manageDistUIState, softwareModuleManagement,
distributionsViewClientCriterion, artifactManagement, swMetadataPopupLayout, artifactUploadState);
this.swModuleTable = new SwModuleTable(eventBus, i18n, uiNotification, manageDistUIState,
softwareModuleManagement, distributionsViewClientCriterion, artifactManagement, swMetadataPopupLayout,
artifactUploadState);
final SoftwareModuleAddUpdateWindow softwareModuleAddUpdateWindow = new SoftwareModuleAddUpdateWindow(i18n,
uiNotification, eventBus, softwareModuleManagement, softwareModuleTypeManagement, entityFactory,
@@ -50,7 +51,7 @@ public class SwModuleTableLayout extends AbstractTableLayout<SwModuleTable> {
super.init(
new SwModuleTableHeader(i18n, permChecker, eventBus, manageDistUIState, softwareModuleAddUpdateWindow),
swModuleTable, new SwModuleDetails(i18n, eventBus, permChecker, softwareModuleAddUpdateWindow,
manageDistUIState, softwareModuleManagement, swMetadataPopupLayout, entityFactory));
manageDistUIState, softwareModuleManagement, swMetadataPopupLayout));
}
public SwModuleTable getSwModuleTable() {

View File

@@ -55,7 +55,7 @@ public class DistSMTypeFilterHeader extends AbstractFilterHeader {
@Override
protected boolean hasCreateUpdatePermission() {
return permChecker.hasCreateDistributionPermission() || permChecker.hasUpdateDistributionPermission();
return permChecker.hasCreateRepositoryPermission() || permChecker.hasUpdateRepositoryPermission();
}
@Override

View File

@@ -78,7 +78,7 @@ public abstract class CreateUpdateTypeLayout<E extends NamedEntity> extends Abst
getPreviewButtonColor(ColorPickerConstants.DEFAULT_COLOR);
tagColorPreviewBtn.setStyleName(TAG_DYNAMIC_STYLE);
createOptionGroup(permChecker.hasCreateDistributionPermission(), permChecker.hasUpdateDistributionPermission());
createOptionGroup(permChecker.hasCreateRepositoryPermission(), permChecker.hasUpdateRepositoryPermission());
}
@Override
@@ -128,8 +128,8 @@ public abstract class CreateUpdateTypeLayout<E extends NamedEntity> extends Abst
super.reset();
typeKey.clear();
restoreComponentStyles();
setOptionGroupDefaultValue(permChecker.hasCreateDistributionPermission(),
permChecker.hasUpdateDistributionPermission());
setOptionGroupDefaultValue(permChecker.hasCreateRepositoryPermission(),
permChecker.hasUpdateRepositoryPermission());
}
/**

View File

@@ -232,7 +232,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
private void buildLayout() {
// Build only if user has both permissions
if (permChecker.hasTargetReadPermission() || permChecker.hasReadDistributionPermission()) {
if (permChecker.hasTargetReadPermission() || permChecker.hasReadRepositoryPermission()) {
setSizeFull();
createMainLayout();
addComponents(mainLayout);
@@ -250,9 +250,9 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
private void layoutWidgets() {
mainLayout.removeAllComponents();
if (permChecker.hasReadDistributionPermission() && permChecker.hasTargetReadPermission()) {
if (permChecker.hasReadRepositoryPermission() && permChecker.hasTargetReadPermission()) {
displayAllWidgets();
} else if (permChecker.hasReadDistributionPermission()) {
} else if (permChecker.hasReadRepositoryPermission()) {
displayDistributionWidgetsOnly();
} else if (permChecker.hasTargetReadPermission()) {
displayTargetWidgetsOnly();
@@ -292,7 +292,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
private Boolean showFooterLayout() {
if (permChecker.hasTargetReadPermission()
|| (permChecker.hasDeleteDistributionPermission() || permChecker.hasDeleteTargetPermission())
|| (permChecker.hasDeleteRepositoryPermission() || permChecker.hasDeleteTargetPermission())
|| hasDeploymentPermission()) {
return true;
}
@@ -300,7 +300,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
}
private boolean hasDeploymentPermission() {
return permChecker.hasReadDistributionPermission() && permChecker.hasUpdateTargetPermission();
return permChecker.hasReadRepositoryPermission() && permChecker.hasUpdateTargetPermission();
}
private void displayTargetWidgetsOnly() {
@@ -318,7 +318,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
}
private void maximizeTargetTable() {
if (permChecker.hasReadDistributionPermission()) {
if (permChecker.hasReadRepositoryPermission()) {
mainLayout.removeComponent(distributionTableLayout);
mainLayout.removeComponent(distributionTagLayout);
}

View File

@@ -10,7 +10,6 @@ package org.eclipse.hawkbit.ui.management.dstable;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.common.detailslayout.AbstractDistributionSetDetails;
import org.eclipse.hawkbit.ui.common.detailslayout.SoftwareModuleDetailsTable;
@@ -30,12 +29,11 @@ public class DistributionDetails extends AbstractDistributionSetDetails {
DistributionDetails(final VaadinMessageSource i18n, final UIEventBus eventBus,
final SpPermissionChecker permissionChecker, final ManagementUIState managementUIState,
final DistributionSetManagement distributionSetManagement,
final DsMetadataPopupLayout dsMetadataPopupLayout, final EntityFactory entityFactory,
final UINotification uiNotification, final DistributionSetTagManagement distributionSetTagManagement,
final DsMetadataPopupLayout dsMetadataPopupLayout, final UINotification uiNotification,
final DistributionSetTagManagement distributionSetTagManagement,
final DistributionAddUpdateWindowLayout distributionAddUpdateWindowLayout) {
super(i18n, eventBus, permissionChecker, managementUIState, distributionAddUpdateWindowLayout,
distributionSetManagement, dsMetadataPopupLayout, entityFactory, uiNotification,
distributionSetTagManagement,
distributionSetManagement, dsMetadataPopupLayout, uiNotification, distributionSetTagManagement,
createSoftwareModuleDetailsTable(i18n, permissionChecker, uiNotification));
restoreState();
}

View File

@@ -56,7 +56,7 @@ public class DistributionTableLayout extends AbstractTableLayout<DistributionTab
super.init(new DistributionTableHeader(i18n, permissionChecker, eventBus, managementUIState), distributionTable,
new DistributionDetails(i18n, eventBus, permissionChecker, managementUIState, distributionSetManagement,
dsMetadataPopupLayout, entityFactory, notification, distributionSetTagManagement,
dsMetadataPopupLayout, notification, distributionSetTagManagement,
distributionAddUpdateWindowLayout));
}

Some files were not shown because too many files have changed in this diff Show More