diff --git a/README.md b/README.md
index bc00c5c8d..778391f32 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,12 @@
-Build: [](https://circleci.com/gh/eclipse/hawkbit)
-
# Eclipse.IoT hawkBit - Update Server
[hawkBit](https://projects.eclipse.org/projects/iot.hawkbit) is an domain independent back end solution for rolling out software updates to constrained edge devices as well as more powerful controllers and gateways connected to IP based networking infrastructure.
+Build: [](https://circleci.com/gh/eclipse/hawkbit)
+[](https://sonar.eu-gb.mybluemix.net)
+
# Documentation
see [hawkBit Wiki](https://github.com/eclipse/hawkbit/wiki)
diff --git a/examples/hawkbit-custom-theme-example/src/main/java/org/eclipse/hawkbit/app/MyUI.java b/examples/hawkbit-custom-theme-example/src/main/java/org/eclipse/hawkbit/app/MyUI.java
index 5ef632d10..964994317 100644
--- a/examples/hawkbit-custom-theme-example/src/main/java/org/eclipse/hawkbit/app/MyUI.java
+++ b/examples/hawkbit-custom-theme-example/src/main/java/org/eclipse/hawkbit/app/MyUI.java
@@ -8,6 +8,8 @@ package org.eclipse.hawkbit.app;
* http://www.eclipse.org/legal/epl-v10.html
*/
+import java.util.concurrent.ScheduledExecutorService;
+
import org.eclipse.hawkbit.ui.HawkbitUI;
import org.eclipse.hawkbit.ui.UIEventProvider;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
@@ -38,8 +40,8 @@ public class MyUI extends HawkbitUI {
private static final long serialVersionUID = 1L;
@Autowired
- public MyUI(final EventBus systemEventBus, final org.vaadin.spring.events.EventBus.SessionEventBus eventBus,
- final UIEventProvider provider) {
- super(new DelayedEventBusPushStrategy(eventBus, systemEventBus, provider));
+ public MyUI(final ScheduledExecutorService executorService, final EventBus systemEventBus,
+ final org.vaadin.spring.events.EventBus.SessionEventBus eventBus, final UIEventProvider provider) {
+ super(new DelayedEventBusPushStrategy(executorService, eventBus, systemEventBus, provider));
}
}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java
index 01a9231e3..e73244247 100644
--- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java
@@ -34,7 +34,6 @@ import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.eclipse.hawkbit.dmf.json.model.Artifact;
-import org.eclipse.hawkbit.dmf.json.model.Artifact.UrlProtocol;
import org.eclipse.hawkbit.dmf.json.model.SoftwareModule;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus;
@@ -206,12 +205,12 @@ public class DeviceSimulatorUpdater {
private static void handleArtifacts(final String targetToken, final List status,
final Artifact artifact) {
- if (artifact.getUrls().containsKey(UrlProtocol.HTTPS)) {
- status.add(downloadUrl(artifact.getUrls().get(UrlProtocol.HTTPS), targetToken,
- artifact.getHashes().getSha1(), artifact.getSize()));
- } else if (artifact.getUrls().containsKey(UrlProtocol.HTTP)) {
- status.add(downloadUrl(artifact.getUrls().get(UrlProtocol.HTTP), targetToken,
- artifact.getHashes().getSha1(), artifact.getSize()));
+ if (artifact.getUrls().containsKey("https")) {
+ status.add(downloadUrl(artifact.getUrls().get("https"), targetToken, artifact.getHashes().getSha1(),
+ artifact.getSize()));
+ } else if (artifact.getUrls().containsKey("http")) {
+ status.add(downloadUrl(artifact.getUrls().get("http"), targetToken, artifact.getHashes().getSha1(),
+ artifact.getSize()));
}
}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java
index 5e9b3e049..6a8826c82 100644
--- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java
@@ -11,7 +11,6 @@ package org.eclipse.hawkbit.simulator.amqp;
import static org.eclipse.hawkbit.simulator.amqp.AmqpProperties.CONFIGURATION_PREFIX;
import java.time.Duration;
-import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
@@ -36,6 +35,8 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.support.RetryTemplate;
+import com.google.common.collect.Maps;
+
/**
* The spring AMQP configuration to use a AMQP for communication with SP update
* server.
@@ -200,13 +201,13 @@ public class AmqpConfiguration {
}
private Map getDeadLetterExchangeArgs() {
- final Map args = new HashMap<>();
+ final Map args = Maps.newHashMapWithExpectedSize(1);
args.put("x-dead-letter-exchange", amqpProperties.getDeadLetterExchange());
return args;
}
private static Map getTTLMaxArgs() {
- final Map args = new HashMap<>();
+ final Map args = Maps.newHashMapWithExpectedSize(2);
args.put("x-message-ttl", Duration.ofDays(1).toMillis());
args.put("x-max-length", 100_000);
return args;
diff --git a/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyUI.java b/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyUI.java
index e5bc7535d..0316b68e5 100644
--- a/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyUI.java
+++ b/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyUI.java
@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.app;
+import java.util.concurrent.ScheduledExecutorService;
+
import org.eclipse.hawkbit.ui.HawkbitUI;
import org.eclipse.hawkbit.ui.UIEventProvider;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
@@ -37,8 +39,8 @@ public class MyUI extends HawkbitUI {
private static final long serialVersionUID = 1L;
@Autowired
- public MyUI(final EventBus systemEventBus, final org.vaadin.spring.events.EventBus.SessionEventBus eventBus,
- final UIEventProvider provider) {
- super(new DelayedEventBusPushStrategy(eventBus, systemEventBus, provider));
+ public MyUI(final ScheduledExecutorService scheduledExecutorService, final EventBus systemEventBus,
+ final org.vaadin.spring.events.EventBus.SessionEventBus eventBus, final UIEventProvider provider) {
+ super(new DelayedEventBusPushStrategy(scheduledExecutorService, eventBus, systemEventBus, provider));
}
}
diff --git a/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties b/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties
index a0cad4e9b..85c47cb8f 100644
--- a/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties
+++ b/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties
@@ -9,8 +9,15 @@
vaadin.servlet.productionMode=true
-hawkbit.artifact.url.coap.enabled=false
-hawkbit.artifact.url.http.enabled=false
-hawkbit.artifact.url.https.enabled=true
-hawkbit.artifact.url.https.pattern={protocol}://{hostname}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}
-hawkbit.artifact.url.https.hostname=hawkbit.eu-gb.mybluemix.net
\ No newline at end of file
+## Configuration for building download URLs - START
+hawkbit.artifact.url.protocols.download-http.rel=download-http
+hawkbit.artifact.url.protocols.download-http.protocol=https
+hawkbit.artifact.url.protocols.download-http.supports=DMF,DDI
+hawkbit.artifact.url.protocols.download-http.hostname=hawkbit.eu-gb.mybluemix.net
+hawkbit.artifact.url.protocols.download-http.ref={protocol}://{hostname}/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}
+hawkbit.artifact.url.protocols.md5sum-http.rel=md5sum-http
+hawkbit.artifact.url.protocols.md5sum-http.protocol=${hawkbit.artifact.url.protocols.download-http.protocol}
+hawkbit.artifact.url.protocols.md5sum-http.supports=DDI
+hawkbit.artifact.url.protocols.md5sum-http.hostname=${hawkbit.artifact.url.protocols.download-http.hostname}
+hawkbit.artifact.url.protocols.md5sum-http.ref=${hawkbit.artifact.url.protocols.download-http.ref}.MD5SUM
+## Configuration for building download URLs - END
diff --git a/examples/hawkbit-example-app/src/main/resources/application.properties b/examples/hawkbit-example-app/src/main/resources/application.properties
index 6e05b6b5a..0c32c8f8c 100644
--- a/examples/hawkbit-example-app/src/main/resources/application.properties
+++ b/examples/hawkbit-example-app/src/main/resources/application.properties
@@ -7,17 +7,15 @@
# http://www.eclipse.org/legal/epl-v10.html
#
+# User Security
+security.user.name=admin
+security.user.password=admin
+
# DDI authentication configuration
hawkbit.server.ddi.security.authentication.anonymous.enabled=true
hawkbit.server.ddi.security.authentication.targettoken.enabled=true
hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=true
-# Download URL generation config
-hawkbit.artifact.url.coap.enabled=false
-hawkbit.artifact.url.http.enabled=true
-hawkbit.artifact.url.http.port=8080
-hawkbit.artifact.url.https.enabled=false
-
## Vaadin configuration
vaadin.servlet.productionMode=false
diff --git a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java
index 7807d0f11..b8aee0f97 100644
--- a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java
+++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java
@@ -50,11 +50,21 @@ public class SoftwareModuleTypeBuilder {
return this;
}
+ /**
+ * @param description
+ * of the module
+ * @return the builder itself
+ */
public SoftwareModuleTypeBuilder description(final String description) {
this.description = description;
return this;
}
+ /**
+ * @param maxAssignments
+ * of a module of that type to the same distribution set
+ * @return the builder itself
+ */
public SoftwareModuleTypeBuilder maxAssignments(final int maxAssignments) {
this.maxAssignments = maxAssignments;
return this;
@@ -99,4 +109,4 @@ public class SoftwareModuleTypeBuilder {
return body;
}
-}
\ No newline at end of file
+}
diff --git a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java
index eabd2b329..4795ba7e7 100644
--- a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java
+++ b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java
@@ -227,7 +227,7 @@ public class ArtifactStore implements ArtifactRepository {
* @return a paged list of artifacts mapped from the given dbFiles
*/
private List map(final List dbFiles) {
- return dbFiles.stream().map(this::map).collect(Collectors.toList());
+ return dbFiles.stream().map(ArtifactStore::map).collect(Collectors.toList());
}
/**
@@ -263,7 +263,7 @@ public class ArtifactStore implements ArtifactRepository {
* the mongoDB gridFs file.
* @return a mapped artifact from the given dbFile
*/
- private GridFsArtifact map(final GridFSFile fsFile) {
+ private static GridFsArtifact map(final GridFSFile fsFile) {
if (fsFile == null) {
return null;
}
diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/CacheAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/CacheAutoConfiguration.java
index a170dfcd3..2d61624cf 100644
--- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/CacheAutoConfiguration.java
+++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/CacheAutoConfiguration.java
@@ -82,8 +82,7 @@ public class CacheAutoConfiguration extends CachingConfigurerSupport {
*/
@Override
public Collection resolveCaches(final CacheOperationInvocationContext> context) {
- return super.resolveCaches(context).stream().map(cache -> new TenantCacheWrapper(cache))
- .collect(Collectors.toList());
+ return super.resolveCaches(context).stream().map(TenantCacheWrapper::new).collect(Collectors.toList());
}
/*
diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementConfiguration.java
index fc979fd67..15a9c5bcc 100644
--- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementConfiguration.java
+++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementConfiguration.java
@@ -13,7 +13,9 @@ import java.util.ArrayList;
import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator;
import org.eclipse.hawkbit.im.authentication.PermissionUtils;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -34,6 +36,9 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@ConditionalOnMissingBean(UserDetailsService.class)
public class InMemoryUserManagementConfiguration extends GlobalAuthenticationConfigurerAdapter {
+ @Autowired
+ private SecurityProperties securityProperties;
+
@Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
final DaoAuthenticationProvider userDaoAuthenticationProvider = new TenantDaoAuthenticationProvider();
@@ -49,7 +54,8 @@ public class InMemoryUserManagementConfiguration extends GlobalAuthenticationCon
public UserDetailsService userDetailsService() {
final InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(new ArrayList<>());
inMemoryUserDetailsManager.setAuthenticationManager(null);
- inMemoryUserDetailsManager.createUser(new User("admin", "admin", PermissionUtils.createAllAuthorityList()));
+ inMemoryUserDetailsManager.createUser(new User(securityProperties.getUser().getName(),
+ securityProperties.getUser().getPassword(), PermissionUtils.createAllAuthorityList()));
return inMemoryUserDetailsManager;
}
diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java
index 9a7c7df52..565b1520a 100644
--- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java
+++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java
@@ -148,7 +148,7 @@ public class SecurityManagedConfiguration {
private DdiSecurityProperties ddiSecurityConfiguration;
@Autowired
- private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
+ private SecurityProperties springSecurityProperties;
@Autowired
private SystemSecurityContext systemSecurityContext;
@@ -478,7 +478,7 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
public void onAuthenticationSuccess(final Authentication authentication) throws Exception {
if (authentication.getClass().equals(TenantUserPasswordAuthenticationToken.class)) {
- systemSecurityContext.runAsSystemAsTenant(() -> systemManagement.getTenantMetadata(),
+ systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata,
((TenantUserPasswordAuthenticationToken) authentication).getTenant().toString());
} else if (authentication.getClass().equals(UsernamePasswordAuthenticationToken.class)) {
// TODO: vaadin4spring-ext-security does not give us the
@@ -489,7 +489,7 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
// vaadin4spring 0.0.7 because it
// has been fixed.
final String defaultTenant = "DEFAULT";
- systemSecurityContext.runAsSystemAsTenant(() -> systemManagement.getTenantMetadata(), defaultTenant);
+ systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, defaultTenant);
}
super.onAuthenticationSuccess(authentication);
@@ -526,7 +526,7 @@ class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
private void lazyCreateTenantMetadata() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.isAuthenticated()) {
- systemSecurityContext.runAsSystem(() -> systemManagement.getTenantMetadata());
+ systemSecurityContext.runAsSystem(systemManagement::getTenantMetadata);
}
}
diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/PropertyHostnameResolverAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/PropertyHostnameResolverAutoConfiguration.java
index 0bd4a8240..e95a0ec35 100644
--- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/PropertyHostnameResolverAutoConfiguration.java
+++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/PropertyHostnameResolverAutoConfiguration.java
@@ -12,8 +12,10 @@ import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.hawkbit.HawkbitServerProperties;
+import org.eclipse.hawkbit.api.ArtifactUrlHandler;
+import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties;
import org.eclipse.hawkbit.api.HostnameResolver;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.eclipse.hawkbit.api.PropertyBasedArtifactUrlHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -22,35 +24,41 @@ import org.springframework.context.annotation.Configuration;
import com.google.common.base.Throwables;
/**
- * Autoconfiguration of the {@link HostnameResolver} based on a property.
- *
- *
- *
+ * Auto configuration for {@link HostnameResolver} and
+ * {@link ArtifactUrlHandler} based on a properties.
*/
@Configuration
-@EnableConfigurationProperties(HawkbitServerProperties.class)
+@EnableConfigurationProperties({ HawkbitServerProperties.class, ArtifactUrlHandlerProperties.class })
public class PropertyHostnameResolverAutoConfiguration {
- @Autowired
- private HawkbitServerProperties serverProperties;
-
/**
+ * @param serverProperties
+ * to get the servers URL
* @return the default autoconfigure hostname resolver implementation which
* is property based specified by the property {@link #url}
*/
@Bean
@ConditionalOnMissingBean(value = HostnameResolver.class)
- public HostnameResolver hostnameResolver() {
- return new HostnameResolver() {
- @Override
- public URL resolveHostname() {
- try {
- return new URL(serverProperties.getUrl());
- } catch (final MalformedURLException e) {
- throw Throwables.propagate(e);
- }
+ public HostnameResolver hostnameResolver(final HawkbitServerProperties serverProperties) {
+ return () -> {
+ try {
+ return new URL(serverProperties.getUrl());
+ } catch (final MalformedURLException e) {
+ throw Throwables.propagate(e);
}
};
}
+ /**
+ * @param urlHandlerProperties
+ * for bean configuration
+ * @return PropertyBasedArtifactUrlHandler bean
+ */
+ @Bean
+ @ConditionalOnMissingBean(ArtifactUrlHandler.class)
+ public PropertyBasedArtifactUrlHandler propertyBasedArtifactUrlHandler(
+ final ArtifactUrlHandlerProperties urlHandlerProperties) {
+ return new PropertyBasedArtifactUrlHandler(urlHandlerProperties);
+ }
+
}
diff --git a/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties b/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties
index cb7793168..3ac45a027 100644
--- a/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties
+++ b/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties
@@ -10,6 +10,10 @@
# Displayed basic auth realm
security.basic.realm=HawkBit
+# User Security
+security.user.name=admin
+security.user.password=admin
+
# JPA / Datasource
spring.jpa.eclipselink.eclipselink.weaving=false
spring.jpa.database=H2
@@ -37,9 +41,25 @@ hawkbit.controller.maxPollingTime=23:59:59
hawkbit.controller.minPollingTime=00:00:30
# Attention: if you want to use a maximumPollingTime greater 23:59:59 you have to update the DurationField in the configuration window
-
# Configuration for RabbitMQ integration
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter_ttl
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver
hawkbit.dmf.rabbitmq.authenticationReceiverQueue=authentication_receiver
+
+# Download URL generation configuration
+hawkbit.artifact.url.protocols.download-http.rel=download-http
+hawkbit.artifact.url.protocols.download-http.hostname=localhost
+hawkbit.artifact.url.protocols.download-http.ip=127.0.0.1
+hawkbit.artifact.url.protocols.download-http.protocol=http
+hawkbit.artifact.url.protocols.download-http.port=8080
+hawkbit.artifact.url.protocols.download-http.supports=DMF,DDI
+hawkbit.artifact.url.protocols.download-http.ref={protocol}://{hostname}:{port}/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}
+hawkbit.artifact.url.protocols.md5sum-http.rel=md5sum-http
+hawkbit.artifact.url.protocols.md5sum-http.protocol=${hawkbit.artifact.url.protocols.download-http.protocol}
+hawkbit.artifact.url.protocols.md5sum-http.hostname=${hawkbit.artifact.url.protocols.download-http.hostname}
+hawkbit.artifact.url.protocols.md5sum-http.ip=${hawkbit.artifact.url.protocols.download-http.ip}
+hawkbit.artifact.url.protocols.md5sum-http.port=${hawkbit.artifact.url.protocols.download-http.port}
+hawkbit.artifact.url.protocols.md5sum-http.supports=DDI
+hawkbit.artifact.url.protocols.md5sum-http.ref=${hawkbit.artifact.url.protocols.download-http.ref}.MD5SUM
+
diff --git a/hawkbit-core/pom.xml b/hawkbit-core/pom.xml
index f9e140d40..b8f339a01 100644
--- a/hawkbit-core/pom.xml
+++ b/hawkbit-core/pom.xml
@@ -33,6 +33,16 @@
guava
+
+ org.easytesting
+ fest-assert-core
+ test
+
+
+ org.easytesting
+ fest-assert
+ test
+
org.springframework.boot
spring-boot-starter-test
diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/UrlProtocol.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ApiType.java
similarity index 64%
rename from hawkbit-core/src/main/java/org/eclipse/hawkbit/api/UrlProtocol.java
rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ApiType.java
index 77c23ad0d..986bef476 100644
--- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/UrlProtocol.java
+++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ApiType.java
@@ -9,8 +9,18 @@
package org.eclipse.hawkbit.api;
/**
- * Represented the supported protocols for artifact url's.
+ * hawkBit API type.
+ *
*/
-public enum UrlProtocol {
- COAP, HTTP, HTTPS
+public enum ApiType {
+
+ /**
+ * Support for Device Management Federation API.
+ */
+ DMF,
+
+ /**
+ * Support for Direct Device Integration API.
+ */
+ DDI;
}
diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrl.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrl.java
new file mode 100644
index 000000000..6d60d01e6
--- /dev/null
+++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrl.java
@@ -0,0 +1,109 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.api;
+
+/**
+ * Container for a generated Artifact URL.
+ *
+ */
+public class ArtifactUrl {
+
+ private final String protocol;
+ private final String rel;
+ private final String ref;
+
+ /**
+ * Constructor.
+ *
+ * @param protocol
+ * string, e.g. ftp, http, https
+ * @param rel
+ * hypermedia value
+ * @param ref
+ * hypermedia value
+ */
+ public ArtifactUrl(final String protocol, final String rel, final String ref) {
+ this.protocol = protocol;
+ this.rel = rel;
+ this.ref = ref;
+ }
+
+ /**
+ * @return protocol name used in DMF API messages.
+ */
+ public String getProtocol() {
+ return protocol;
+ }
+
+ /**
+ * @return rel links value useful in hypermedia.
+ */
+ public String getRel() {
+ return rel;
+ }
+
+ /**
+ * @return generated artifact download URL
+ */
+ public String getRef() {
+ return ref;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((protocol == null) ? 0 : protocol.hashCode());
+ result = prime * result + ((ref == null) ? 0 : ref.hashCode());
+ result = prime * result + ((rel == null) ? 0 : rel.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 ArtifactUrl other = (ArtifactUrl) obj;
+ if (protocol == null) {
+ if (other.protocol != null) {
+ return false;
+ }
+ } else if (!protocol.equals(other.protocol)) {
+ return false;
+ }
+ if (ref == null) {
+ if (other.ref != null) {
+ return false;
+ }
+ } else if (!ref.equals(other.ref)) {
+ return false;
+ }
+ if (rel == null) {
+ if (other.rel != null) {
+ return false;
+ }
+ } else if (!rel.equals(other.rel)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "ArtifactUrl [protocol=" + protocol + ", rel=" + rel + ", ref=" + ref + "]";
+ }
+
+}
diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java
index 03492122c..8f2036c82 100644
--- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java
+++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java
@@ -8,36 +8,26 @@
*/
package org.eclipse.hawkbit.api;
+import java.util.List;
+
/**
* Interface declaration of the {@link ArtifactUrlHandler} which generates the
* URLs to specific artifacts.
*
*/
+@FunctionalInterface
public interface ArtifactUrlHandler {
/**
* Returns a generated download URL for a given artifact parameters for a
* specific protocol.
*
- * @param controllerId
- * the authenticated controller id
- * @param softwareModuleId
- * the softwareModuleId belonging to the artifact
- * @param filename
- * the filename of the artifact
- * @param sha1Hash
- * the sha1Hash of the artifact
- * @param protocol
- * the protocol the URL should be generated
+ * @param placeholder
+ * data for URL generation
+ * @param api
+ * given protocol that URL needs to support
+ *
* @return an URL for the given artifact parameters in a given protocol
*/
- String getUrl(String controllerId, final Long softwareModuleId, final String filename, final String sha1Hash,
- final UrlProtocol protocol);
-
- /**
- * @param protocol
- * to check support for
- * @return true of the handler supports given protocol.
- */
- boolean protocolSupported(UrlProtocol protocol);
+ List getUrls(URLPlaceholder placeholder, ApiType api);
}
diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java
index 490b2d102..86b9e7d79 100644
--- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java
+++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java
@@ -8,90 +8,153 @@
*/
package org.eclipse.hawkbit.api;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import org.springframework.boot.context.properties.ConfigurationProperties;
+import com.google.common.collect.Lists;
+
/**
* Artifact handler properties class for holding all supported protocols with
* host, ip, port and download pattern.
+ *
+ * @see PropertyBasedArtifactUrlHandler
*/
@ConfigurationProperties("hawkbit.artifact.url")
public class ArtifactUrlHandlerProperties {
- private final Http http = new Http();
- private final Https https = new Https();
- private final Coap coap = new Coap();
-
- public Http getHttp() {
- return http;
- }
-
- public Https getHttps() {
- return https;
- }
-
- public Coap getCoap() {
- return coap;
- }
+ /**
+ * Rel as key and complete protocol as value.
+ */
+ private final Map protocols = new HashMap<>();
/**
- * @param protocol
- * the protocol schema to retrieve the properties.
- * @return the properties to a protocol or {@code null} if protocol does not
- * have properties or protocol not supported
+ * Protocol specific properties to generate URLs accordingly.
+ *
*/
- public ProtocolProperties getProperties(final String protocol) {
- switch (protocol) {
- case "http":
- return getHttp();
- case "https":
- return getHttps();
- case "coap":
- return getCoap();
- default:
- return null;
- }
- }
+ public static class UrlProtocol {
- /**
- * Object to hold the properties for the HTTP protocol.
- */
- public static class Http extends DefaultProtocolProperties {
+ private static final int DEFAULT_HTTP_PORT = 8080;
/**
- * Constructor.
+ * Set to true if enabled.
*/
- public Http() {
- setPattern(
- "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}");
- }
- }
-
- /**
- * Object to hold the properties for the HTTP protocol.
- */
- public static class Https extends DefaultProtocolProperties {
+ private boolean enabled = true;
/**
- * Constructor.
+ * Hypermedia rel value for this protocol.
*/
- public Https() {
- setPattern(
- "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}");
- }
- }
-
- /**
- * Object to hold the properties for the HTTP protocol.
- */
- public static class Coap extends DefaultProtocolProperties {
+ private String rel = "download-http";
/**
- * Constructor.
+ * Hypermedia ref pattern for this protocol. Supported place holders are
+ * protocol,controllerId,targetId,targetIdBase62,ip,port,hostname,
+ * artifactFileName,artifactSHA1,
+ * artifactIdBase62,artifactId,tenant,softwareModuleId,
+ * softwareModuleIdBase62.
+ *
+ * The update server itself supports
*/
- public Coap() {
- setPattern("{protocol}://{ip}:{port}/fw/{tenant}/{targetId}/sha1/{artifactSHA1}");
- setPort("5683");
+ private String ref = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}";
+
+ /**
+ * Protocol name placeholder that can be used in ref pattern.
+ */
+ private String protocol = "http";
+
+ /**
+ * Hostname placeholder that can be used in ref pattern.
+ */
+ private String hostname = "localhost";
+
+ /**
+ * IP address placeholder that can be used in ref pattern.
+ */
+ // Exception squid:S1313 - default only, can be configured
+ @SuppressWarnings("squid:S1313")
+ private String ip = "127.0.0.1";
+
+ /**
+ * Port placeholder that can be used in ref pattern.
+ */
+ private Integer port = DEFAULT_HTTP_PORT;
+
+ /**
+ * Support for the following hawkBit API.
+ */
+ private List supports = Lists.newArrayList(ApiType.DDI, ApiType.DMF);
+
+ public boolean isEnabled() {
+ return enabled;
}
+
+ public void setEnabled(final boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public String getRel() {
+ return rel;
+ }
+
+ public void setRel(final String rel) {
+ this.rel = rel;
+ }
+
+ public String getRef() {
+ return ref;
+ }
+
+ public void setRef(final String ref) {
+ this.ref = ref;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(final String hostname) {
+ this.hostname = hostname;
+ }
+
+ public String getIp() {
+ return ip;
+ }
+
+ public void setIp(final String ip) {
+ this.ip = ip;
+ }
+
+ public Integer getPort() {
+ return port;
+ }
+
+ public void setPort(final Integer port) {
+ this.port = port;
+ }
+
+ public List getSupports() {
+ return Collections.unmodifiableList(supports);
+ }
+
+ public void setSupports(final List supports) {
+ this.supports = Collections.unmodifiableList(supports);
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+
+ public void setProtocol(final String protocol) {
+ this.protocol = protocol;
+ }
+
+ }
+
+ public Map getProtocols() {
+ return protocols;
}
}
diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/Base62Util.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/Base62Util.java
new file mode 100644
index 000000000..37952b6a2
--- /dev/null
+++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/Base62Util.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.api;
+
+/**
+ * Utility class for Base10 to Base62 conversion and vice versa. Base62 has the
+ * benefit of being shorter in ASCII representation than Base10.
+ */
+public final class Base62Util {
+ private static final String BASE62_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ private static final int BASE62_BASE = BASE62_ALPHABET.length();
+
+ private Base62Util() {
+ // Utility class
+ }
+
+ /**
+ * @param base10
+ * number
+ * @return converted number into Base62 ASCII string
+ */
+ public static String fromBase10(final long base10) {
+ if (base10 == 0) {
+ return "0";
+ }
+
+ long temp = base10;
+ final StringBuilder sb = new StringBuilder();
+
+ while (temp > 0) {
+ temp = fromBase10(temp, sb);
+ }
+ return sb.reverse().toString();
+ }
+
+ /**
+ * @param base62
+ * number
+ * @return converted number into Base10
+ */
+ public static Long toBase10(final String base62) {
+ return toBase10(new StringBuilder(base62).reverse().toString().toCharArray());
+ }
+
+ private static Long fromBase10(final long base10, final StringBuilder sb) {
+ final int rem = (int) (base10 % BASE62_BASE);
+ sb.append(BASE62_ALPHABET.charAt(rem));
+ return base10 / BASE62_BASE;
+ }
+
+ private static Long toBase10(final char[] chars) {
+ long base10 = 0L;
+ for (int i = chars.length - 1; i >= 0; i--) {
+ base10 += toBase10(BASE62_ALPHABET.indexOf(chars[i]), i);
+ }
+ return base10;
+ }
+
+ private static int toBase10(final int n, final int pow) {
+ return n * (int) Math.pow(BASE62_BASE, pow);
+ }
+}
diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/DefaultProtocolProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/DefaultProtocolProperties.java
deleted file mode 100644
index 07eac8db1..000000000
--- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/DefaultProtocolProperties.java
+++ /dev/null
@@ -1,79 +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.api;
-
-/**
- * Object to hold the properties for the base protocols.
- */
-public class DefaultProtocolProperties implements ProtocolProperties {
- // The IP address is not hardcoded. It's the default value, if the IP
- // address is not configured.
- @SuppressWarnings("squid:S1313")
- private static final String DEFAULT_IP_LOCALHOST = "127.0.0.1";
- private static final String LOCALHOST = "localhost";
-
- private String hostname = LOCALHOST;
- private String ip = DEFAULT_IP_LOCALHOST;
- private String port = "";
- /**
- * An ant-URL pattern with placeholder to build the URL on. The URL can have
- * specific artifact placeholder.
- */
- private String pattern;
-
- /**
- * Enables protocol.
- */
- private boolean enabled = true;
-
- @Override
- public boolean isEnabled() {
- return enabled;
- }
-
- public void setEnabled(final boolean enabled) {
- this.enabled = enabled;
- }
-
- @Override
- public String getHostname() {
- return hostname;
- }
-
- public void setHostname(final String hostname) {
- this.hostname = hostname;
- }
-
- @Override
- public String getIp() {
- return ip;
- }
-
- public void setIp(final String ip) {
- this.ip = ip;
- }
-
- @Override
- public String getPattern() {
- return pattern;
- }
-
- public void setPattern(final String urlPattern) {
- this.pattern = urlPattern;
- }
-
- @Override
- public String getPort() {
- return port;
- }
-
- public void setPort(final String port) {
- this.port = port;
- }
-}
diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java
index 91a271541..229438477 100644
--- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java
+++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java
@@ -9,55 +9,80 @@
package org.eclipse.hawkbit.api;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.stream.Collectors;
-import org.eclipse.hawkbit.tenancy.TenantAware;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.stereotype.Component;
+import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties.UrlProtocol;
import com.google.common.base.Strings;
import com.google.common.net.UrlEscapers;
/**
* Implementation for ArtifactUrlHandler for creating urls to download resource
- * based on pattern.
+ * based on patterns configured by {@link ArtifactUrlHandlerProperties}.
+ *
+ * This mechanism can be used to generate links to arbitrary file hosting
+ * infrastructure. However, the hawkBit update server supports hosting files as
+ * well in the following {@link UrlProtocol#getRef()} patterns:
+ *
+ * Default:
+ * {protocol}://{hostname}:{port}/{tenant}/controller/v1/{controllerId}/
+ * softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}
+ *
+ * Default (MD5SUM files):
+ * {protocol}://{hostname}:{port}/{tenant}/controller/v1/{controllerId}/
+ * softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}.MD5SUM
+ *
*/
-@Component
-@EnableConfigurationProperties(ArtifactUrlHandlerProperties.class)
public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
private static final String PROTOCOL_PLACEHOLDER = "protocol";
- private static final String TARGET_ID_PLACEHOLDER = "targetId";
+ private static final String CONTROLLER_ID_PLACEHOLDER = "controllerId";
+ private static final String TARGET_ID_BASE10_PLACEHOLDER = "targetId";
+ private static final String TARGET_ID_BASE62_PLACEHOLDER = "targetIdBase62";
private static final String IP_PLACEHOLDER = "ip";
private static final String PORT_PLACEHOLDER = "port";
private static final String HOSTNAME_PLACEHOLDER = "hostname";
private static final String ARTIFACT_FILENAME_PLACEHOLDER = "artifactFileName";
private static final String ARTIFACT_SHA1_PLACEHOLDER = "artifactSHA1";
+ private static final String ARTIFACT_ID_BASE10_PLACEHOLDER = "artifactId";
+ private static final String ARTIFACT_ID_BASE62_PLACEHOLDER = "artifactIdBase62";
private static final String TENANT_PLACEHOLDER = "tenant";
- private static final String SOFTWARE_MODULE_ID_PLACDEHOLDER = "softwareModuleId";
+ private static final String TENANT_ID_BASE10_PLACEHOLDER = "tenantId";
+ private static final String TENANT_ID_BASE62_PLACEHOLDER = "tenantIdBase62";
+ private static final String SOFTWARE_MODULE_ID_BASE10_PLACDEHOLDER = "softwareModuleId";
+ private static final String SOFTWARE_MODULE_ID_BASE62_PLACDEHOLDER = "softwareModuleIdBase62";
- @Autowired
- private ArtifactUrlHandlerProperties urlHandlerProperties;
+ private final ArtifactUrlHandlerProperties urlHandlerProperties;
- @Autowired
- private TenantAware tenantAware;
+ /**
+ * @param urlHandlerProperties
+ * for URL generation configuration
+ */
+ public PropertyBasedArtifactUrlHandler(final ArtifactUrlHandlerProperties urlHandlerProperties) {
+ this.urlHandlerProperties = urlHandlerProperties;
+ }
@Override
- public String getUrl(final String targetId, final Long softwareModuleId, final String filename,
- final String sha1Hash, final UrlProtocol protocol) {
+ public List getUrls(final URLPlaceholder placeholder, final ApiType api) {
- final String protocolString = protocol.name().toLowerCase();
- final ProtocolProperties properties = urlHandlerProperties.getProperties(protocolString);
- if (properties == null || properties.getPattern() == null) {
- return null;
- }
+ return urlHandlerProperties.getProtocols().entrySet().stream()
+ .filter(entry -> entry.getValue().getSupports().contains(api))
+ .filter(entry -> entry.getValue().isEnabled())
+ .map(entry -> new ArtifactUrl(entry.getValue().getProtocol(), entry.getValue().getRel(),
+ generateUrl(entry.getValue(), placeholder)))
+ .collect(Collectors.toList());
+
+ }
+
+ private static String generateUrl(final UrlProtocol protocol, final URLPlaceholder placeholder) {
+ final Set> entrySet = getReplaceMap(protocol, placeholder).entrySet();
+
+ String urlPattern = protocol.getRef();
- String urlPattern = properties.getPattern();
- final Set> entrySet = getReplaceMap(targetId, softwareModuleId,
- UrlEscapers.urlFragmentEscaper().escape(filename), sha1Hash, protocolString, properties).entrySet();
for (final Entry entry : entrySet) {
if (entry.getKey().equals(PORT_PLACEHOLDER)) {
urlPattern = urlPattern.replace(":{" + entry.getKey() + "}",
@@ -69,30 +94,29 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
return urlPattern;
}
- private Map getReplaceMap(final String targetId, final Long softwareModuleId, final String filename,
- final String sha1Hash, final String protocol, final ProtocolProperties properties) {
+ private static Map getReplaceMap(final UrlProtocol protocol, final URLPlaceholder placeholder) {
final Map replaceMap = new HashMap<>();
- replaceMap.put(IP_PLACEHOLDER, properties.getIp());
- replaceMap.put(HOSTNAME_PLACEHOLDER, properties.getHostname());
- replaceMap.put(ARTIFACT_FILENAME_PLACEHOLDER, filename);
- replaceMap.put(ARTIFACT_SHA1_PLACEHOLDER, sha1Hash);
- replaceMap.put(PROTOCOL_PLACEHOLDER, protocol);
- replaceMap.put(PORT_PLACEHOLDER, properties.getPort());
- replaceMap.put(TENANT_PLACEHOLDER, tenantAware.getCurrentTenant());
- replaceMap.put(TARGET_ID_PLACEHOLDER, targetId);
- replaceMap.put(SOFTWARE_MODULE_ID_PLACDEHOLDER, String.valueOf(softwareModuleId));
+ replaceMap.put(IP_PLACEHOLDER, protocol.getIp());
+ replaceMap.put(HOSTNAME_PLACEHOLDER, protocol.getHostname());
+ replaceMap.put(ARTIFACT_FILENAME_PLACEHOLDER,
+ UrlEscapers.urlFragmentEscaper().escape(placeholder.getSoftwareData().getFilename()));
+ replaceMap.put(ARTIFACT_SHA1_PLACEHOLDER, placeholder.getSoftwareData().getSha1Hash());
+ replaceMap.put(PROTOCOL_PLACEHOLDER, protocol.getProtocol());
+ replaceMap.put(PORT_PLACEHOLDER, protocol.getPort() == null ? null : String.valueOf(protocol.getPort()));
+ replaceMap.put(TENANT_PLACEHOLDER, placeholder.getTenant());
+ replaceMap.put(TENANT_ID_BASE10_PLACEHOLDER, String.valueOf(placeholder.getTenantId()));
+ replaceMap.put(TENANT_ID_BASE62_PLACEHOLDER, Base62Util.fromBase10(placeholder.getTenantId()));
+ replaceMap.put(CONTROLLER_ID_PLACEHOLDER, placeholder.getControllerId());
+ replaceMap.put(TARGET_ID_BASE10_PLACEHOLDER, String.valueOf(placeholder.getTargetId()));
+ replaceMap.put(TARGET_ID_BASE62_PLACEHOLDER, Base62Util.fromBase10(placeholder.getTargetId()));
+ replaceMap.put(ARTIFACT_ID_BASE62_PLACEHOLDER,
+ Base62Util.fromBase10(placeholder.getSoftwareData().getArtifactId()));
+ replaceMap.put(ARTIFACT_ID_BASE10_PLACEHOLDER, String.valueOf(placeholder.getSoftwareData().getArtifactId()));
+ replaceMap.put(SOFTWARE_MODULE_ID_BASE10_PLACDEHOLDER,
+ String.valueOf(placeholder.getSoftwareData().getSoftwareModuleId()));
+ replaceMap.put(SOFTWARE_MODULE_ID_BASE62_PLACDEHOLDER,
+ Base62Util.fromBase10(placeholder.getSoftwareData().getSoftwareModuleId()));
return replaceMap;
}
- @Override
- public boolean protocolSupported(final UrlProtocol protocol) {
- final String protocolString = protocol.name().toLowerCase();
- final ProtocolProperties properties = urlHandlerProperties.getProperties(protocolString);
- if (properties == null || properties.getPattern() == null) {
- return false;
- }
-
- return properties.isEnabled();
- }
-
}
diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/URLPlaceholder.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/URLPlaceholder.java
new file mode 100644
index 000000000..43d51db5c
--- /dev/null
+++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/URLPlaceholder.java
@@ -0,0 +1,247 @@
+/**
+ * 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.api;
+
+/**
+ * Container for variables available to the {@link ArtifactUrlHandler}.
+ *
+ */
+public class URLPlaceholder {
+ private final String tenant;
+ private final Long tenantId;
+ private final String controllerId;
+ private final Long targetId;
+ private final SoftwareData softwareData;
+
+ /**
+ * Constructor.
+ *
+ * @param tenant
+ * of the client
+ * @param tenantId
+ * of teh tenant
+ * @param controllerId
+ * of the target
+ * @param targetId
+ * of the target
+ * @param softwareData
+ * information about the artifact and software module that can be
+ * accessed by the URL.
+ */
+ public URLPlaceholder(final String tenant, final Long tenantId, final String controllerId, final Long targetId,
+ final SoftwareData softwareData) {
+ this.tenant = tenant;
+ this.tenantId = tenantId;
+ this.controllerId = controllerId;
+ this.targetId = targetId;
+ this.softwareData = softwareData;
+ }
+
+ /**
+ * Information about the artifact and software module that can be accessed
+ * by the URL.
+ *
+ */
+ public static class SoftwareData {
+ private Long softwareModuleId;
+ private String filename;
+ private Long artifactId;
+ private String sha1Hash;
+
+ /**
+ * Constructor.
+ *
+ * @param softwareModuleId
+ * of the module the artifact belongs to
+ * @param filename
+ * of the artifact
+ * @param artifactId
+ * of the artifact
+ * @param sha1Hash
+ * of the artifact
+ */
+ public SoftwareData(final Long softwareModuleId, final String filename, final Long artifactId,
+ final String sha1Hash) {
+ this.softwareModuleId = softwareModuleId;
+ this.filename = filename;
+ this.artifactId = artifactId;
+ this.sha1Hash = sha1Hash;
+ }
+
+ public Long getSoftwareModuleId() {
+ return softwareModuleId;
+ }
+
+ public void setSoftwareModuleId(final Long softwareModuleId) {
+ this.softwareModuleId = softwareModuleId;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public void setFilename(final String filename) {
+ this.filename = filename;
+ }
+
+ public Long getArtifactId() {
+ return artifactId;
+ }
+
+ public void setArtifactId(final Long artifactId) {
+ this.artifactId = artifactId;
+ }
+
+ public String getSha1Hash() {
+ return sha1Hash;
+ }
+
+ public void setSha1Hash(final String sha1Hash) {
+ this.sha1Hash = sha1Hash;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((artifactId == null) ? 0 : artifactId.hashCode());
+ result = prime * result + ((filename == null) ? 0 : filename.hashCode());
+ result = prime * result + ((sha1Hash == null) ? 0 : sha1Hash.hashCode());
+ result = prime * result + ((softwareModuleId == null) ? 0 : softwareModuleId.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 SoftwareData other = (SoftwareData) obj;
+ if (artifactId == null) {
+ if (other.artifactId != null) {
+ return false;
+ }
+ } else if (!artifactId.equals(other.artifactId)) {
+ return false;
+ }
+ if (filename == null) {
+ if (other.filename != null) {
+ return false;
+ }
+ } else if (!filename.equals(other.filename)) {
+ return false;
+ }
+ if (sha1Hash == null) {
+ if (other.sha1Hash != null) {
+ return false;
+ }
+ } else if (!sha1Hash.equals(other.sha1Hash)) {
+ return false;
+ }
+ if (softwareModuleId == null) {
+ if (other.softwareModuleId != null) {
+ return false;
+ }
+ } else if (!softwareModuleId.equals(other.softwareModuleId)) {
+ return false;
+ }
+ return true;
+ }
+
+ }
+
+ public String getTenant() {
+ return tenant;
+ }
+
+ public Long getTenantId() {
+ return tenantId;
+ }
+
+ public String getControllerId() {
+ return controllerId;
+ }
+
+ public Long getTargetId() {
+ return targetId;
+ }
+
+ public SoftwareData getSoftwareData() {
+ return softwareData;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((controllerId == null) ? 0 : controllerId.hashCode());
+ result = prime * result + ((softwareData == null) ? 0 : softwareData.hashCode());
+ result = prime * result + ((targetId == null) ? 0 : targetId.hashCode());
+ result = prime * result + ((tenant == null) ? 0 : tenant.hashCode());
+ result = prime * result + ((tenantId == null) ? 0 : tenantId.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 URLPlaceholder other = (URLPlaceholder) obj;
+ if (controllerId == null) {
+ if (other.controllerId != null) {
+ return false;
+ }
+ } else if (!controllerId.equals(other.controllerId)) {
+ return false;
+ }
+ if (softwareData == null) {
+ if (other.softwareData != null) {
+ return false;
+ }
+ } else if (!softwareData.equals(other.softwareData)) {
+ return false;
+ }
+ if (targetId == null) {
+ if (other.targetId != null) {
+ return false;
+ }
+ } else if (!targetId.equals(other.targetId)) {
+ return false;
+ }
+ if (tenant == null) {
+ if (other.tenant != null) {
+ return false;
+ }
+ } else if (!tenant.equals(other.tenant)) {
+ return false;
+ }
+ if (tenantId == null) {
+ if (other.tenantId != null) {
+ return false;
+ }
+ } else if (!tenantId.equals(other.tenantId)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationKey.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationKey.java
index d68e963be..d5995da59 100644
--- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationKey.java
+++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationKey.java
@@ -90,7 +90,7 @@ public enum TenantConfigurationKey {
* @param validator
* Validator which validates, that property is of correct format
*/
- private TenantConfigurationKey(final String key, final String defaultKeyName, final Class> dataType,
+ TenantConfigurationKey(final String key, final String defaultKeyName, final Class> dataType,
final String defaultValue, final Class extends TenantConfigurationValidator> validator) {
this.keyName = key;
this.dataType = dataType;
diff --git a/hawkbit-core/src/test/java/org/eclipse/hawkbit/api/Base62UtilTest.java b/hawkbit-core/src/test/java/org/eclipse/hawkbit/api/Base62UtilTest.java
new file mode 100644
index 000000000..c9c11d10c
--- /dev/null
+++ b/hawkbit-core/src/test/java/org/eclipse/hawkbit/api/Base62UtilTest.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.api;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+import ru.yandex.qatools.allure.annotations.Description;
+import ru.yandex.qatools.allure.annotations.Features;
+import ru.yandex.qatools.allure.annotations.Stories;
+
+@Features("Unit Tests - Artifact URL Handler")
+@Stories("Base62 Utility tests")
+public class Base62UtilTest {
+
+ @Test
+ @Description("Convert Base10 numbres to Base62 ASCII strings.")
+ public void fromBase10() {
+ assertThat(Base62Util.fromBase10(0L)).isEqualTo("0");
+ assertThat(Base62Util.fromBase10(11L)).isEqualTo("B");
+ assertThat(Base62Util.fromBase10(36L)).isEqualTo("a");
+ assertThat(Base62Util.fromBase10(999L)).isEqualTo("G7");
+ }
+
+ @Test
+ @Description("Convert Base62 ASCII strings to Base10 numbers.")
+ public void toBase10() {
+ assertThat(Base62Util.toBase10("0")).isEqualTo(0L);
+ assertThat(Base62Util.toBase10("B")).isEqualTo(11);
+ assertThat(Base62Util.toBase10("a")).isEqualTo(36L);
+ assertThat(Base62Util.toBase10("G7")).isEqualTo(999L);
+ }
+}
diff --git a/hawkbit-core/src/test/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandlerTest.java b/hawkbit-core/src/test/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandlerTest.java
new file mode 100644
index 000000000..3d7fc18af
--- /dev/null
+++ b/hawkbit-core/src/test/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandlerTest.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.api;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties.UrlProtocol;
+import org.eclipse.hawkbit.api.URLPlaceholder.SoftwareData;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+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;
+
+/**
+ * Tests for creating urls to download artifacts.
+ */
+@Features("Unit Tests - Artifact URL Handler")
+@Stories("Test to generate the artifact download URL")
+@RunWith(MockitoJUnitRunner.class)
+public class PropertyBasedArtifactUrlHandlerTest {
+
+ private static final String TEST_PROTO = "coap";
+ private static final String TEST_REL = "download-udp";
+
+ private static final long TENANT_ID = 456789L;
+ private static final String CONTROLLER_ID = "Test";
+ private static final String FILENAME = "Afile1234";
+ private static final long SOFTWAREMODULEID = 87654L;
+ private static final long TARGETID = 3474366L;
+ private static final String TARGETID_BASE62 = "EZqA";
+ private static final String SHA1HASH = "test12345";
+ private static final long ARTIFACTID = 1345678L;
+ private static final String ARTIFACTID_BASE62 = "5e4U";
+ private static final String TENANT = "TEST_TENANT";
+
+ private static final String HTTP_LOCALHOST = "http://localhost:8080/";
+
+ private ArtifactUrlHandler urlHandlerUnderTest;
+
+ private ArtifactUrlHandlerProperties properties;
+
+ private static URLPlaceholder placeholder = new URLPlaceholder(TENANT, TENANT_ID, CONTROLLER_ID, TARGETID,
+ new SoftwareData(SOFTWAREMODULEID, FILENAME, ARTIFACTID, SHA1HASH));
+
+ @Before
+ public void setup() {
+ properties = new ArtifactUrlHandlerProperties();
+ urlHandlerUnderTest = new PropertyBasedArtifactUrlHandler(properties);
+
+ }
+
+ @Test
+ @Description("Tests the generation of http download url.")
+ public void urlGenerationWithDefaultConfiguration() {
+ properties.getProtocols().put("download-http", new UrlProtocol());
+
+ final List ddiUrls = urlHandlerUnderTest.getUrls(placeholder, ApiType.DDI);
+ assertEquals(
+ Lists.newArrayList(new ArtifactUrl("http", "download-http", HTTP_LOCALHOST + TENANT + "/controller/v1/"
+ + CONTROLLER_ID + "/softwaremodules/" + SOFTWAREMODULEID + "/artifacts/" + FILENAME)),
+ ddiUrls);
+
+ final List dmfUrls = urlHandlerUnderTest.getUrls(placeholder, ApiType.DMF);
+ assertEquals(ddiUrls, dmfUrls);
+ }
+
+ @Test
+ @Description("Tests the generation of custom download url with a CoAP example that supports DMF only.")
+ public void urlGenerationWithCustomConfiguration() {
+ final UrlProtocol proto = new UrlProtocol();
+ proto.setIp("127.0.0.1");
+ proto.setPort(5683);
+ proto.setProtocol(TEST_PROTO);
+ proto.setRel(TEST_REL);
+ proto.setSupports(Lists.newArrayList(ApiType.DMF));
+ proto.setRef("{protocol}://{ip}:{port}/fw/{tenant}/{controllerId}/sha1/{artifactSHA1}");
+ properties.getProtocols().put(TEST_PROTO, proto);
+
+ List urls = urlHandlerUnderTest.getUrls(placeholder, ApiType.DDI);
+
+ assertThat(urls).isEmpty();
+ urls = urlHandlerUnderTest.getUrls(placeholder, ApiType.DMF);
+
+ assertEquals(Lists.newArrayList(new ArtifactUrl(TEST_PROTO, TEST_REL,
+ "coap://127.0.0.1:5683/fw/" + TENANT + "/" + CONTROLLER_ID + "/sha1/" + SHA1HASH)), urls);
+ }
+
+ @Test
+ @Description("Tests the generation of custom download url using Base62 references with a CoAP example that supports DMF only.")
+ public void urlGenerationWithCustomShortConfiguration() {
+ final UrlProtocol proto = new UrlProtocol();
+ proto.setIp("127.0.0.1");
+ proto.setPort(5683);
+ proto.setProtocol(TEST_PROTO);
+ proto.setRel(TEST_REL);
+ proto.setSupports(Lists.newArrayList(ApiType.DMF));
+ proto.setRef("{protocol}://{ip}:{port}/fws/{tenant}/{targetIdBase62}/{artifactIdBase62}");
+ properties.getProtocols().put("ftp", proto);
+
+ List urls = urlHandlerUnderTest.getUrls(placeholder, ApiType.DDI);
+
+ assertThat(urls).isEmpty();
+ urls = urlHandlerUnderTest.getUrls(placeholder, ApiType.DMF);
+
+ assertEquals(Lists.newArrayList(new ArtifactUrl(TEST_PROTO, TEST_REL,
+ TEST_PROTO + "://127.0.0.1:5683/fws/" + TENANT + "/" + TARGETID_BASE62 + "/" + ARTIFACTID_BASE62)),
+ urls);
+ }
+}
diff --git a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiCancelActionToStop.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiCancelActionToStop.java
index 3ab8d6b55..45932ff25 100644
--- a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiCancelActionToStop.java
+++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiCancelActionToStop.java
@@ -25,7 +25,6 @@ public class DdiCancelActionToStop {
* ID of the action to be stoppedW
*/
public DdiCancelActionToStop(final String stopId) {
- super();
this.stopId = stopId;
}
diff --git a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiChunk.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiChunk.java
index cf146b597..8f1172c39 100644
--- a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiChunk.java
+++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiChunk.java
@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.ddi.json.model;
+import java.util.Collections;
import java.util.List;
import javax.validation.constraints.NotNull;
@@ -65,7 +66,11 @@ public class DdiChunk {
}
public List getArtifacts() {
- return artifacts;
+ if (artifacts == null) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(artifacts);
}
}
diff --git a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiConfig.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiConfig.java
index 0dfed6e79..d01b9f277 100644
--- a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiConfig.java
+++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiConfig.java
@@ -30,7 +30,6 @@ public class DdiConfig {
* configuration of the SP target
*/
public DdiConfig(final DdiPolling polling) {
- super();
this.polling = polling;
}
diff --git a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiDeployment.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiDeployment.java
index c7e364b36..2f7fd593e 100644
--- a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiDeployment.java
+++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiDeployment.java
@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.ddi.json.model;
+import java.util.Collections;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonValue;
@@ -41,7 +42,6 @@ public class DdiDeployment {
* to handle.
*/
public DdiDeployment(final HandlingType download, final HandlingType update, final List chunks) {
- super();
this.download = download;
this.update = update;
this.chunks = chunks;
@@ -56,7 +56,11 @@ public class DdiDeployment {
}
public List getChunks() {
- return chunks;
+ if (chunks == null) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(chunks);
}
/**
@@ -81,7 +85,7 @@ public class DdiDeployment {
private String name;
- private HandlingType(final String name) {
+ HandlingType(final String name) {
this.name = name;
}
diff --git a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiResult.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiResult.java
index 36f0d134c..6d5085569 100644
--- a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiResult.java
+++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiResult.java
@@ -71,7 +71,7 @@ public class DdiResult {
private String name;
- private FinalResult(final String name) {
+ FinalResult(final String name) {
this.name = name;
}
diff --git a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiStatus.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiStatus.java
index cb9b57187..140ba08e0 100644
--- a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiStatus.java
+++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/json/model/DdiStatus.java
@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.ddi.json.model;
+import java.util.Collections;
import java.util.List;
import javax.validation.constraints.NotNull;
@@ -57,7 +58,11 @@ public class DdiStatus {
}
public List getDetails() {
- return details;
+ if (details == null) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(details);
}
/**
@@ -98,7 +103,7 @@ public class DdiStatus {
private String name;
- private ExecutionStatus(final String name) {
+ ExecutionStatus(final String name) {
this.name = name;
}
diff --git a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRootControllerRestApi.java b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRootControllerRestApi.java
index f67e0591b..432cd7e4a 100644
--- a/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRootControllerRestApi.java
+++ b/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRootControllerRestApi.java
@@ -37,39 +37,45 @@ public interface DdiRootControllerRestApi {
/**
* Returns all artifacts of a given software module and target.
- *
- * @param targetid
+ *
+ * @param tenant
+ * of the client
+ * @param controllerId
* of the target that matches to controller id
* @param softwareModuleId
* of the software module
* @return the response
*/
- @RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts", produces = {
+ @RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/softwaremodules/{softwareModuleId}/artifacts", produces = {
"application/hal+json", MediaType.APPLICATION_JSON_VALUE })
- ResponseEntity> getSoftwareModulesArtifacts(
- @PathVariable("tenant") final String tenant, @PathVariable("targetid") final String targetid,
+ ResponseEntity> getSoftwareModulesArtifacts(@PathVariable("tenant") final String tenant,
+ @PathVariable("controllerId") final String controllerId,
@PathVariable("softwareModuleId") final Long softwareModuleId);
/**
* Root resource for an individual {@link Target}.
*
- * @param targetid
+ * @param tenant
+ * of the request
+ * @param controllerId
* of the target that matches to controller id
* @param request
* the HTTP request injected by spring
* @return the response
*/
- @RequestMapping(method = RequestMethod.GET, value = "/{targetid}", produces = { "application/hal+json",
+ @RequestMapping(method = RequestMethod.GET, value = "/{controllerId}", produces = { "application/hal+json",
MediaType.APPLICATION_JSON_VALUE })
ResponseEntity getControllerBase(@PathVariable("tenant") final String tenant,
- @PathVariable("targetid") final String targetid);
+ @PathVariable("controllerId") final String controllerId);
/**
* Handles GET {@link DdiArtifact} download request. This could be full or
* partial (as specified by RFC7233 (Range Requests)) download request.
*
- * @param targetid
- * of the related target
+ * @param tenant
+ * of the request
+ * @param controllerId
+ * of the target
* @param softwareModuleId
* of the parent software module
* @param fileName
@@ -83,17 +89,19 @@ public interface DdiRootControllerRestApi {
* {@link HttpStatus#OK} or in case of partial download
* {@link HttpStatus#PARTIAL_CONTENT}.
*/
- @RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{fileName}")
+ @RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{fileName}")
ResponseEntity downloadArtifact(@PathVariable("tenant") final String tenant,
- @PathVariable("targetid") final String targetid,
+ @PathVariable("controllerId") final String controllerId,
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("fileName") final String fileName);
/**
* Handles GET {@link DdiArtifact} MD5 checksum file download request.
*
- * @param targetid
- * of the related target
+ * @param tenant
+ * of the request
+ * @param controllerId
+ * of the target
* @param softwareModuleId
* of the parent software module
* @param fileName
@@ -106,18 +114,20 @@ public interface DdiRootControllerRestApi {
* @return {@link ResponseEntity} with status {@link HttpStatus#OK} if
* successful
*/
- @RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{fileName}"
+ @RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{fileName}"
+ DdiRestConstants.ARTIFACT_MD5_DWNL_SUFFIX, produces = MediaType.TEXT_PLAIN_VALUE)
ResponseEntity downloadArtifactMd5(@PathVariable("tenant") final String tenant,
- @PathVariable("targetid") final String targetid,
+ @PathVariable("controllerId") final String controllerId,
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("fileName") final String fileName);
/**
* Resource for software module.
*
- * @param targetid
- * of the target that matches to controller id
+ * @param tenant
+ * of the request
+ * @param controllerId
+ * of the target
* @param actionId
* of the {@link DdiDeploymentBase} that matches to active
* actions.
@@ -129,19 +139,21 @@ public interface DdiRootControllerRestApi {
* the HTTP request injected by spring
* @return the response
*/
- @RequestMapping(value = "/{targetid}/" + DdiRestConstants.DEPLOYMENT_BASE_ACTION
+ @RequestMapping(value = "/{controllerId}/" + DdiRestConstants.DEPLOYMENT_BASE_ACTION
+ "/{actionId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity getControllerBasedeploymentAction(@PathVariable("tenant") final String tenant,
- @PathVariable("targetid") @NotEmpty final String targetid,
+ @PathVariable("controllerId") @NotEmpty final String controllerId,
@PathVariable("actionId") @NotEmpty final Long actionId,
@RequestParam(value = "c", required = false, defaultValue = "-1") final int resource);
/**
* This is the feedback channel for the {@link DdiDeploymentBase} action.
*
+ * @param tenant
+ * of the client
* @param feedback
* to provide
- * @param targetid
+ * @param controllerId
* of the target that matches to controller id
* @param actionId
* of the action we have feedback for
@@ -150,33 +162,37 @@ public interface DdiRootControllerRestApi {
*
* @return the response
*/
- @RequestMapping(value = "/{targetid}/" + DdiRestConstants.DEPLOYMENT_BASE_ACTION + "/{actionId}/"
+ @RequestMapping(value = "/{controllerId}/" + DdiRestConstants.DEPLOYMENT_BASE_ACTION + "/{actionId}/"
+ DdiRestConstants.FEEDBACK, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
- ResponseEntity postBasedeploymentActionFeedback(@PathVariable("tenant") final String tenant,
- @Valid final DdiActionFeedback feedback, @PathVariable("targetid") final String targetid,
+ ResponseEntity postBasedeploymentActionFeedback(@Valid final DdiActionFeedback feedback,
+ @PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId,
@PathVariable("actionId") @NotEmpty final Long actionId);
/**
* This is the feedback channel for the config data action.
*
+ * @param tenant
+ * of the client
* @param configData
* as body
- * @param targetid
+ * @param controllerId
* to provide data for
* @param request
* the HTTP request injected by spring
*
* @return status of the request
*/
- @RequestMapping(value = "/{targetid}/"
+ @RequestMapping(value = "/{controllerId}/"
+ DdiRestConstants.CONFIG_DATA_ACTION, method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
- ResponseEntity putConfigData(@PathVariable("tenant") final String tenant,
- @Valid final DdiConfigData configData, @PathVariable("targetid") final String targetid);
+ ResponseEntity putConfigData(@Valid final DdiConfigData configData,
+ @PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId);
/**
* RequestMethod.GET method for the {@link DdiCancel} action.
*
- * @param targetid
+ * @param tenant
+ * of the request
+ * @param controllerId
* ID of the calling target
* @param actionId
* of the action
@@ -185,19 +201,21 @@ public interface DdiRootControllerRestApi {
*
* @return the {@link DdiCancel} response
*/
- @RequestMapping(value = "/{targetid}/" + DdiRestConstants.CANCEL_ACTION
+ @RequestMapping(value = "/{controllerId}/" + DdiRestConstants.CANCEL_ACTION
+ "/{actionId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity getControllerCancelAction(@PathVariable("tenant") final String tenant,
- @PathVariable("targetid") @NotEmpty final String targetid,
+ @PathVariable("controllerId") @NotEmpty final String controllerId,
@PathVariable("actionId") @NotEmpty final Long actionId);
/**
* RequestMethod.POST method receiving the {@link DdiActionFeedback} from
* the target.
*
+ * @param tenant
+ * of the client
* @param feedback
* the {@link DdiActionFeedback} from the target.
- * @param targetid
+ * @param controllerId
* the ID of the calling target
* @param actionId
* of the action we have feedback for
@@ -207,10 +225,11 @@ public interface DdiRootControllerRestApi {
* @return the {@link DdiActionFeedback} response
*/
- @RequestMapping(value = "/{targetid}/" + DdiRestConstants.CANCEL_ACTION + "/{actionId}/"
+ @RequestMapping(value = "/{controllerId}/" + DdiRestConstants.CANCEL_ACTION + "/{actionId}/"
+ DdiRestConstants.FEEDBACK, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
- ResponseEntity postCancelActionFeedback(@PathVariable("tenant") final String tenant,
- @Valid final DdiActionFeedback feedback, @PathVariable("targetid") @NotEmpty final String targetid,
+ ResponseEntity postCancelActionFeedback(@Valid final DdiActionFeedback feedback,
+ @PathVariable("tenant") final String tenant,
+ @PathVariable("controllerId") @NotEmpty final String controllerId,
@PathVariable("actionId") @NotEmpty final Long actionId);
}
diff --git a/hawkbit-ddi-dl-api/src/main/java/org/eclipse/hawkbit/ddi/dl/rest/api/DdiDlArtifactStoreControllerRestApi.java b/hawkbit-ddi-dl-api/src/main/java/org/eclipse/hawkbit/ddi/dl/rest/api/DdiDlArtifactStoreControllerRestApi.java
index 726f5de57..0d60eb7a2 100644
--- a/hawkbit-ddi-dl-api/src/main/java/org/eclipse/hawkbit/ddi/dl/rest/api/DdiDlArtifactStoreControllerRestApi.java
+++ b/hawkbit-ddi-dl-api/src/main/java/org/eclipse/hawkbit/ddi/dl/rest/api/DdiDlArtifactStoreControllerRestApi.java
@@ -12,7 +12,7 @@ import java.io.InputStream;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -27,7 +27,9 @@ public interface DdiDlArtifactStoreControllerRestApi {
/**
* Handles GET download request. This could be full or partial download
* request.
- *
+ *
+ * @param tenant
+ * name of the client
* @param fileName
* to search for
* @param targetid
@@ -40,12 +42,14 @@ public interface DdiDlArtifactStoreControllerRestApi {
@RequestMapping(method = RequestMethod.GET, value = DdiDlRestConstants.ARTIFACT_DOWNLOAD_BY_FILENAME
+ "/{fileName}")
@ResponseBody
- public ResponseEntity downloadArtifactByFilename(@PathVariable("tenant") final String tenant,
+ ResponseEntity downloadArtifactByFilename(@PathVariable("tenant") final String tenant,
@PathVariable("fileName") final String fileName, @AuthenticationPrincipal final String targetid);
/**
* Handles GET MD5 checksum file download request.
*
+ * @param tenant
+ * name of the client
* @param fileName
* to search for
*
@@ -54,7 +58,7 @@ public interface DdiDlArtifactStoreControllerRestApi {
@RequestMapping(method = RequestMethod.GET, value = DdiDlRestConstants.ARTIFACT_DOWNLOAD_BY_FILENAME + "/{fileName}"
+ DdiDlRestConstants.ARTIFACT_MD5_DWNL_SUFFIX)
@ResponseBody
- public ResponseEntity downloadArtifactMD5ByFilename(@PathVariable("tenant") final String tenant,
+ ResponseEntity downloadArtifactMD5ByFilename(@PathVariable("tenant") final String tenant,
@PathVariable("fileName") final String fileName);
}
diff --git a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DataConversionHelper.java b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DataConversionHelper.java
index 55be6f58a..a09155739 100644
--- a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DataConversionHelper.java
+++ b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DataConversionHelper.java
@@ -12,15 +12,16 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
+import org.eclipse.hawkbit.api.ApiType;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
-import org.eclipse.hawkbit.api.UrlProtocol;
+import org.eclipse.hawkbit.api.URLPlaceholder;
+import org.eclipse.hawkbit.api.URLPlaceholder.SoftwareData;
import org.eclipse.hawkbit.ddi.dl.rest.api.DdiDlRestConstants;
import org.eclipse.hawkbit.ddi.json.model.DdiArtifact;
import org.eclipse.hawkbit.ddi.json.model.DdiArtifactHash;
@@ -29,6 +30,7 @@ import org.eclipse.hawkbit.ddi.json.model.DdiConfig;
import org.eclipse.hawkbit.ddi.json.model.DdiControllerBase;
import org.eclipse.hawkbit.ddi.json.model.DdiPolling;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
+import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.Target;
@@ -46,11 +48,11 @@ public final class DataConversionHelper {
}
- static List createChunks(final String targetid, final Action uAction,
- final ArtifactUrlHandler artifactUrlHandler) {
+ static List createChunks(final Target target, final Action uAction,
+ final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement) {
return uAction.getDistributionSet().getModules().stream()
.map(module -> new DdiChunk(mapChunkLegacyKeys(module.getType().getKey()), module.getVersion(),
- module.getName(), createArtifacts(targetid, module, artifactUrlHandler)))
+ module.getName(), createArtifacts(target, module, artifactUrlHandler, systemManagement)))
.collect(Collectors.toList());
}
@@ -69,43 +71,42 @@ public final class DataConversionHelper {
/**
* Creates all (rest) artifacts for a given software module.
*
- * @param targetid
- * of the target
+ * @param target
+ * for create URLs for
* @param module
* the software module
+ * @param artifactUrlHandler
+ * for creating download URLs
+ * @param systemManagement
+ * for access to tenant meta data
* @return a list of artifacts or a empty list. Cannot be .
*/
- public static List createArtifacts(final String targetid,
+ public static List createArtifacts(final Target target,
final org.eclipse.hawkbit.repository.model.SoftwareModule module,
- final ArtifactUrlHandler artifactUrlHandler) {
- final List files = new ArrayList<>();
+ final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement) {
- module.getLocalArtifacts()
- .forEach(artifact -> files.add(createArtifact(targetid, artifactUrlHandler, artifact)));
- return files;
+ return module.getLocalArtifacts().stream()
+ .map(artifact -> createArtifact(target, artifactUrlHandler, artifact, systemManagement))
+ .collect(Collectors.toList());
}
- private static DdiArtifact createArtifact(final String targetid, final ArtifactUrlHandler artifactUrlHandler,
- final LocalArtifact artifact) {
+ private static DdiArtifact createArtifact(final Target target, final ArtifactUrlHandler artifactUrlHandler,
+ final LocalArtifact artifact, final SystemManagement systemManagement) {
final DdiArtifact file = new DdiArtifact();
file.setHashes(new DdiArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash()));
file.setFilename(artifact.getFilename());
file.setSize(artifact.getSize());
- if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTP)) {
- final String linkHttp = artifactUrlHandler.getUrl(targetid, artifact.getSoftwareModule().getId(),
- artifact.getFilename(), artifact.getSha1Hash(), UrlProtocol.HTTP);
- file.add(new Link(linkHttp).withRel("download-http"));
- file.add(new Link(linkHttp + DdiDlRestConstants.ARTIFACT_MD5_DWNL_SUFFIX).withRel("md5sum-http"));
- }
+ artifactUrlHandler
+ .getUrls(new URLPlaceholder(systemManagement.getTenantMetadata().getTenant(),
+ systemManagement.getTenantMetadata().getId(), target.getControllerId(), target.getId(),
+ new SoftwareData(artifact.getSoftwareModule().getId(), artifact.getFilename(), artifact.getId(),
+ artifact.getSha1Hash())),
+ ApiType.DDI)
+ .forEach(entry -> file.add(new Link(entry.getRef()).withRel(entry.getRel())));
- if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTPS)) {
- final String linkHttps = artifactUrlHandler.getUrl(targetid, artifact.getSoftwareModule().getId(),
- artifact.getFilename(), artifact.getSha1Hash(), UrlProtocol.HTTPS);
- file.add(new Link(linkHttps).withRel("download"));
- file.add(new Link(linkHttps + DdiDlRestConstants.ARTIFACT_MD5_DWNL_SUFFIX).withRel("md5sum"));
- }
return file;
+
}
static DdiControllerBase fromTarget(final Target target, final Optional action,
@@ -133,8 +134,8 @@ public final class DataConversionHelper {
}
if (target.getTargetInfo().isRequestControllerAttributes()) {
- result.add(linkTo(methodOn(DdiRootController.class, tenantAware.getCurrentTenant())
- .putConfigData(tenantAware.getCurrentTenant(), null, target.getControllerId()))
+ result.add(linkTo(methodOn(DdiRootController.class, tenantAware.getCurrentTenant()).putConfigData(null,
+ tenantAware.getCurrentTenant(), target.getControllerId()))
.withRel(DdiRestConstants.CONFIG_DATA_ACTION));
}
return result;
diff --git a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactStoreController.java b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactStoreController.java
index 3feb3068f..d3f57a7f7 100644
--- a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactStoreController.java
+++ b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactStoreController.java
@@ -35,7 +35,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
diff --git a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java
index 33d7daf69..7506ddb17 100644
--- a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java
+++ b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java
@@ -33,6 +33,7 @@ import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.SoftwareManagement;
+import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
@@ -88,6 +89,9 @@ public class DdiRootController implements DdiRootControllerRestApi {
@Autowired
private TenantAware tenantAware;
+ @Autowired
+ private SystemManagement systemManagement;
+
@Autowired
private ArtifactUrlHandler artifactUrlHandler;
@@ -99,9 +103,12 @@ public class DdiRootController implements DdiRootControllerRestApi {
@Override
public ResponseEntity> getSoftwareModulesArtifacts(
- @PathVariable("tenant") final String tenant, @PathVariable("targetid") final String targetid,
+ @PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId,
@PathVariable("softwareModuleId") final Long softwareModuleId) {
- LOG.debug("getSoftwareModulesArtifacts({})", targetid);
+ LOG.debug("getSoftwareModulesArtifacts({})", controllerId);
+
+ final Target target = controllerManagement.updateLastTargetQuery(controllerId, IpUtil
+ .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
final SoftwareModule softwareModule = softwareManagement.findSoftwareModuleById(softwareModuleId);
@@ -111,20 +118,21 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
- return new ResponseEntity<>(DataConversionHelper.createArtifacts(targetid, softwareModule, artifactUrlHandler),
+ return new ResponseEntity<>(
+ DataConversionHelper.createArtifacts(target, softwareModule, artifactUrlHandler, systemManagement),
HttpStatus.OK);
}
@Override
public ResponseEntity getControllerBase(@PathVariable("tenant") final String tenant,
- @PathVariable("targetid") final String targetid) {
- LOG.debug("getControllerBase({})", targetid);
+ @PathVariable("controllerId") final String controllerId) {
+ LOG.debug("getControllerBase({})", controllerId);
- final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(targetid, IpUtil
+ final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(controllerId, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
if (target.getTargetInfo().getUpdateStatus() == TargetUpdateStatus.UNKNOWN) {
- LOG.debug("target with {} extsisted but was in status UNKNOWN -> REGISTERED)", targetid);
+ LOG.debug("target with {} extsisted but was in status UNKNOWN -> REGISTERED)", controllerId);
controllerManagement.updateTargetStatus(target.getTargetInfo(), TargetUpdateStatus.REGISTERED,
System.currentTimeMillis(), IpUtil.getClientIpFromRequest(
requestResponseContextHolder.getHttpServletRequest(), securityProperties));
@@ -138,12 +146,12 @@ public class DdiRootController implements DdiRootControllerRestApi {
@Override
public ResponseEntity downloadArtifact(@PathVariable("tenant") final String tenant,
- @PathVariable("targetid") final String targetid,
+ @PathVariable("controllerId") final String controllerId,
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("fileName") final String fileName) {
ResponseEntity result;
- final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil
+ final Target target = controllerManagement.updateLastTargetQuery(controllerId, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId);
@@ -151,7 +159,12 @@ public class DdiRootController implements DdiRootControllerRestApi {
LOG.warn("Softare module with id {} could not be found.", softwareModuleId);
result = new ResponseEntity<>(HttpStatus.NOT_FOUND);
} else {
+
+ // Exception squid:S3655 - Optional access is checked in checkModule
+ // subroutine
+ @SuppressWarnings("squid:S3655")
final LocalArtifact artifact = module.getLocalArtifactByFilename(fileName).get();
+
final DbArtifact file = artifactManagement.loadLocalArtifactBinary(artifact);
final String ifMatch = requestResponseContextHolder.getHttpServletRequest().getHeader("If-Match");
@@ -196,11 +209,14 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
@Override
+ // Exception squid:S3655 - Optional access is checked in checkModule
+ // subroutine
+ @SuppressWarnings("squid:S3655")
public ResponseEntity downloadArtifactMd5(@PathVariable("tenant") final String tenant,
- @PathVariable("targetid") final String targetid,
+ @PathVariable("controllerId") final String controllerId,
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("fileName") final String fileName) {
- controllerManagement.updateLastTargetQuery(targetid, IpUtil
+ controllerManagement.updateLastTargetQuery(controllerId, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId);
@@ -223,12 +239,12 @@ public class DdiRootController implements DdiRootControllerRestApi {
@Override
public ResponseEntity getControllerBasedeploymentAction(
- @PathVariable("tenant") final String tenant, @PathVariable("targetid") final String targetid,
+ @PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId,
@PathVariable("actionId") final Long actionId,
@RequestParam(value = "c", required = false, defaultValue = "-1") final int resource) {
- LOG.debug("getControllerBasedeploymentAction({},{})", targetid, resource);
+ LOG.debug("getControllerBasedeploymentAction({},{})", controllerId, resource);
- final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil
+ final Target target = controllerManagement.updateLastTargetQuery(controllerId, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
final Action action = findActionWithExceptionIfNotFound(actionId);
@@ -239,14 +255,15 @@ public class DdiRootController implements DdiRootControllerRestApi {
if (!action.isCancelingOrCanceled()) {
- final List chunks = DataConversionHelper.createChunks(targetid, action, artifactUrlHandler);
+ final List chunks = DataConversionHelper.createChunks(target, action, artifactUrlHandler,
+ systemManagement);
final HandlingType handlingType = action.isForce() ? HandlingType.FORCED : HandlingType.ATTEMPT;
final DdiDeploymentBase base = new DdiDeploymentBase(Long.toString(action.getId()),
new DdiDeployment(handlingType, handlingType, chunks));
- LOG.debug("Found an active UpdateAction for target {}. returning deyploment: {}", targetid, base);
+ LOG.debug("Found an active UpdateAction for target {}. returning deyploment: {}", controllerId, base);
controllerManagement.registerRetrieved(action, RepositoryConstants.SERVER_MESSAGE_PREFIX
+ "Target retrieved update action and should start now the download.");
@@ -258,12 +275,12 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
@Override
- public ResponseEntity postBasedeploymentActionFeedback(@PathVariable("tenant") final String tenant,
- @Valid @RequestBody final DdiActionFeedback feedback, @PathVariable("targetid") final String targetid,
+ public ResponseEntity postBasedeploymentActionFeedback(@Valid @RequestBody final DdiActionFeedback feedback,
+ @PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId,
@PathVariable("actionId") @NotEmpty final Long actionId) {
- LOG.debug("provideBasedeploymentActionFeedback for target [{},{}]: {}", targetid, actionId, feedback);
+ LOG.debug("provideBasedeploymentActionFeedback for target [{},{}]: {}", controllerId, actionId, feedback);
- final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil
+ final Target target = controllerManagement.updateLastTargetQuery(controllerId, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
if (!actionId.equals(feedback.getId())) {
@@ -285,13 +302,14 @@ public class DdiRootController implements DdiRootControllerRestApi {
return new ResponseEntity<>(HttpStatus.GONE);
}
- controllerManagement.addUpdateActionStatus(generateUpdateStatus(feedback, targetid, feedback.getId(), action));
+ controllerManagement
+ .addUpdateActionStatus(generateUpdateStatus(feedback, controllerId, feedback.getId(), action));
return new ResponseEntity<>(HttpStatus.OK);
}
- private ActionStatus generateUpdateStatus(final DdiActionFeedback feedback, final String targetid,
+ private ActionStatus generateUpdateStatus(final DdiActionFeedback feedback, final String controllerId,
final Long actionid, final Action action) {
final ActionStatus actionStatus = entityFactory.generateActionStatus();
@@ -300,22 +318,22 @@ public class DdiRootController implements DdiRootControllerRestApi {
switch (feedback.getStatus().getExecution()) {
case CANCELED:
- LOG.debug("Controller confirmed cancel (actionid: {}, targetid: {}) as we got {} report.", actionid,
- targetid, feedback.getStatus().getExecution());
+ LOG.debug("Controller confirmed cancel (actionid: {}, controllerId: {}) as we got {} report.", actionid,
+ controllerId, feedback.getStatus().getExecution());
actionStatus.setStatus(Status.CANCELED);
actionStatus.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target confirmed cancelation.");
break;
case REJECTED:
- LOG.info("Controller reported internal error (actionid: {}, targetid: {}) as we got {} report.", actionid,
- targetid, feedback.getStatus().getExecution());
+ LOG.info("Controller reported internal error (actionid: {}, controllerId: {}) as we got {} report.",
+ actionid, controllerId, feedback.getStatus().getExecution());
actionStatus.setStatus(Status.WARNING);
actionStatus.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target REJECTED update.");
break;
case CLOSED:
- handleClosedUpdateStatus(feedback, targetid, actionid, actionStatus);
+ handleClosedUpdateStatus(feedback, controllerId, actionid, actionStatus);
break;
default:
- handleDefaultUpdateStatus(feedback, targetid, actionid, actionStatus);
+ handleDefaultUpdateStatus(feedback, controllerId, actionid, actionStatus);
break;
}
@@ -331,19 +349,19 @@ public class DdiRootController implements DdiRootControllerRestApi {
return actionStatus;
}
- private static void handleDefaultUpdateStatus(final DdiActionFeedback feedback, final String targetid,
+ private static void handleDefaultUpdateStatus(final DdiActionFeedback feedback, final String controllerId,
final Long actionid, final ActionStatus actionStatus) {
- LOG.debug("Controller reported intermediate status (actionid: {}, targetid: {}) as we got {} report.", actionid,
- targetid, feedback.getStatus().getExecution());
+ LOG.debug("Controller reported intermediate status (actionid: {}, controllerId: {}) as we got {} report.",
+ actionid, controllerId, feedback.getStatus().getExecution());
actionStatus.setStatus(Status.RUNNING);
actionStatus.addMessage(
RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target reported " + feedback.getStatus().getExecution());
}
- private static void handleClosedUpdateStatus(final DdiActionFeedback feedback, final String targetid,
+ private static void handleClosedUpdateStatus(final DdiActionFeedback feedback, final String controllerId,
final Long actionid, final ActionStatus actionStatus) {
- LOG.debug("Controller reported closed (actionid: {}, targetid: {}) as we got {} report.", actionid, targetid,
- feedback.getStatus().getExecution());
+ LOG.debug("Controller reported closed (actionid: {}, controllerId: {}) as we got {} report.", actionid,
+ controllerId, feedback.getStatus().getExecution());
if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) {
actionStatus.setStatus(Status.ERROR);
actionStatus.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target reported CLOSED with ERROR!");
@@ -354,23 +372,23 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
@Override
- public ResponseEntity putConfigData(@PathVariable("tenant") final String tenant,
- @Valid @RequestBody final DdiConfigData configData, @PathVariable("targetid") final String targetid) {
- controllerManagement.updateLastTargetQuery(targetid, IpUtil
+ public ResponseEntity putConfigData(@Valid @RequestBody final DdiConfigData configData,
+ @PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId) {
+ controllerManagement.updateLastTargetQuery(controllerId, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
- controllerManagement.updateControllerAttributes(targetid, configData.getData());
+ controllerManagement.updateControllerAttributes(controllerId, configData.getData());
return new ResponseEntity<>(HttpStatus.OK);
}
@Override
public ResponseEntity getControllerCancelAction(@PathVariable("tenant") final String tenant,
- @PathVariable("targetid") @NotEmpty final String targetid,
+ @PathVariable("controllerId") @NotEmpty final String controllerId,
@PathVariable("actionId") @NotEmpty final Long actionId) {
- LOG.debug("getControllerCancelAction({})", targetid);
+ LOG.debug("getControllerCancelAction({})", controllerId);
- final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil
+ final Target target = controllerManagement.updateLastTargetQuery(controllerId, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
final Action action = findActionWithExceptionIfNotFound(actionId);
@@ -383,7 +401,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
final DdiCancel cancel = new DdiCancel(String.valueOf(action.getId()),
new DdiCancelActionToStop(String.valueOf(action.getId())));
- LOG.debug("Found an active CancelAction for target {}. returning cancel: {}", targetid, cancel);
+ LOG.debug("Found an active CancelAction for target {}. returning cancel: {}", controllerId, cancel);
controllerManagement.registerRetrieved(action, RepositoryConstants.SERVER_MESSAGE_PREFIX
+ "Target retrieved cancel action and should start now the cancelation.");
@@ -395,13 +413,13 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
@Override
- public ResponseEntity postCancelActionFeedback(@PathVariable("tenant") final String tenant,
- @Valid @RequestBody final DdiActionFeedback feedback,
- @PathVariable("targetid") @NotEmpty final String targetid,
+ public ResponseEntity postCancelActionFeedback(@Valid @RequestBody final DdiActionFeedback feedback,
+ @PathVariable("tenant") final String tenant,
+ @PathVariable("controllerId") @NotEmpty final String controllerId,
@PathVariable("actionId") @NotEmpty final Long actionId) {
- LOG.debug("provideCancelActionFeedback for target [{}]: {}", targetid, feedback);
+ LOG.debug("provideCancelActionFeedback for target [{}]: {}", controllerId, feedback);
- final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil
+ final Target target = controllerManagement.updateLastTargetQuery(controllerId, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
if (!actionId.equals(feedback.getId())) {
@@ -432,13 +450,13 @@ public class DdiRootController implements DdiRootControllerRestApi {
switch (feedback.getStatus().getExecution()) {
case CANCELED:
LOG.error(
- "Controller reported cancel for a cancel which is not supported by the server (actionid: {}, targetid: {}) as we got {} report.",
+ "Controller reported cancel for a cancel which is not supported by the server (actionid: {}, controllerId: {}) as we got {} report.",
actionid, target.getControllerId(), feedback.getStatus().getExecution());
actionStatus.setStatus(Status.WARNING);
break;
case REJECTED:
- LOG.info("Controller rejected the cancelation request (too late) (actionid: {}, targetid: {}).", actionid,
- target.getControllerId());
+ LOG.info("Controller rejected the cancelation request (too late) (actionid: {}, controllerId: {}).",
+ actionid, target.getControllerId());
actionStatus.setStatus(Status.WARNING);
break;
case CLOSED:
diff --git a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java
index f9625dff7..f97d57bc3 100644
--- a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java
+++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java
@@ -61,8 +61,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
@Stories("Deployment Action Resource")
public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoDB {
- private static final String HTTP_LOCALHOST = "http://localhost/";
- private static final String HTTPS_LOCALHOST = "https://localhost/";
+ private static final String HTTP_LOCALHOST = "http://localhost:8080/";
@Test()
@Description("Ensures that artifacts are not found, when softare module does not exists.")
@@ -174,25 +173,14 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
.andExpect(
jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0].hashes.sha1",
contains(artifact.getSha1Hash())))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.download.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1")))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.md5sum.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1.MD5SUM")))
-
.andExpect(
- jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.download-http.href",
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.download.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1")))
.andExpect(
- jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.md5sum-http.href",
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.md5sum.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
@@ -203,27 +191,17 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
contains("test1.signature")))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1].hashes.md5",
contains(artifactSignature.getMd5Hash())))
+ .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1].hashes.sha1",
+ contains(artifactSignature.getSha1Hash())))
+
.andExpect(
- jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1].hashes.sha1",
- contains(artifactSignature.getSha1Hash())))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.download.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1.signature")))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.md5sum.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1.signature.MD5SUM")))
- .andExpect(
- jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.download-http.href",
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.download.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature")))
.andExpect(
- jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.md5sum-http.href",
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.md5sum.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
@@ -359,16 +337,18 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
.andExpect(
jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0].hashes.sha1",
contains(artifact.getSha1Hash())))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.download.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1")))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.md5sum.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1.MD5SUM")))
+ .andExpect(
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.download.href",
+ contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ + "/controller/v1/4712/softwaremodules/"
+ + findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ + "/artifacts/test1")))
+ .andExpect(
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.md5sum.href",
+ contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ + "/controller/v1/4712/softwaremodules/"
+ + findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ + "/artifacts/test1.MD5SUM")))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1].size", contains(5 * 1024)))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1].filename",
contains("test1.signature")))
@@ -377,24 +357,14 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
.andExpect(
jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1].hashes.sha1",
contains(artifactSignature.getSha1Hash())))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.download.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1.signature")))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.md5sum.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1.signature.MD5SUM")))
.andExpect(
- jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.download-http.href",
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.download.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature")))
.andExpect(
- jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.md5sum-http.href",
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.md5sum.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
@@ -486,31 +456,22 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0].filename", contains("test1")))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0].hashes.md5",
contains(artifact.getMd5Hash())))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0].hashes.sha1",
- contains(artifact.getSha1Hash())))
-
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.download.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1")))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.md5sum.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1.MD5SUM")))
.andExpect(
- jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.download-http.href",
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0].hashes.sha1",
+ contains(artifact.getSha1Hash())))
+ .andExpect(
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.download.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1")))
.andExpect(
- jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.md5sum-http.href",
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[0]._links.md5sum.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.MD5SUM")))
+
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1].size", contains(5 * 1024)))
.andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1].filename",
contains("test1.signature")))
@@ -519,25 +480,14 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
.andExpect(
jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1].hashes.sha1",
contains(artifactSignature.getSha1Hash())))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.download.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1.signature")))
- .andExpect(jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.md5sum.href",
- contains(HTTPS_LOCALHOST + tenantAware.getCurrentTenant()
- + "/controller/v1/4712/softwaremodules/"
- + findDistributionSetByAction.findFirstModuleByType(osType).getId()
- + "/artifacts/test1.signature.MD5SUM")))
-
.andExpect(
- jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.download-http.href",
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.download.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature")))
.andExpect(
- jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.md5sum-http.href",
+ jsonPath("$.deployment.chunks[?(@.part==os)].artifacts[1]._links.md5sum.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
diff --git a/hawkbit-ddi-resource/src/test/resources/application-test.properties b/hawkbit-ddi-resource/src/test/resources/application-test.properties
new file mode 100644
index 000000000..599441734
--- /dev/null
+++ b/hawkbit-ddi-resource/src/test/resources/application-test.properties
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+
+spring.data.mongodb.uri=mongodb://localhost/spArtifactRepository${random.value}
+spring.data.mongodb.port=28017
+
+hawkbit.server.ddi.security.authentication.header.enabled=true
+hawkbit.server.ddi.security.authentication.gatewaytoken.name=TestToken
+
+multipart.max-file-size=5MB
+
+hawkbit.server.security.dos.maxStatusEntriesPerAction=100
+
+hawkbit.server.security.dos.maxAttributeEntriesPerTarget=10
+
+spring.jpa.database=H2
+spring.datasource.url=jdbc:h2:mem:sp-db;DB_CLOSE_ON_EXIT=FALSE
+spring.datasource.driverClassName=org.h2.Driver
+spring.datasource.username=sa
+spring.datasource.password=sa
+
+flyway.enabled=true
+flyway.sqlMigrationSuffix=${spring.jpa.database}.sql
+#spring.jpa.show-sql=true
+
+# DDI configuration
+hawkbit.controller.pollingTime=00:01:00
+hawkbit.controller.pollingOverdueTime=00:01:00
+
+hawkbit.artifact.url.protocols[0].rel=download
+hawkbit.artifact.url.protocols[0].protocol=http
+hawkbit.artifact.url.protocols[0].supports=DMF,DDI
+hawkbit.artifact.url.protocols[0].ref={protocol}://{hostname}:{port}/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}
+hawkbit.artifact.url.protocols[1].rel=md5sum
+hawkbit.artifact.url.protocols[1].protocol=${hawkbit.artifact.url.protocols[0].protocol}
+hawkbit.artifact.url.protocols[1].supports=${hawkbit.artifact.url.protocols[0].supports}
+hawkbit.artifact.url.protocols[1].ref=${hawkbit.artifact.url.protocols[0].ref}.MD5SUM
\ No newline at end of file
diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpAuthenticationMessageHandler.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpAuthenticationMessageHandler.java
new file mode 100644
index 000000000..fc73116f7
--- /dev/null
+++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpAuthenticationMessageHandler.java
@@ -0,0 +1,236 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.amqp;
+
+import java.net.URISyntaxException;
+import java.util.UUID;
+
+import org.eclipse.hawkbit.api.HostnameResolver;
+import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
+import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
+import org.eclipse.hawkbit.cache.DownloadArtifactCache;
+import org.eclipse.hawkbit.cache.DownloadType;
+import org.eclipse.hawkbit.dmf.json.model.Artifact;
+import org.eclipse.hawkbit.dmf.json.model.ArtifactHash;
+import org.eclipse.hawkbit.dmf.json.model.DownloadResponse;
+import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
+import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource;
+import org.eclipse.hawkbit.repository.ArtifactManagement;
+import org.eclipse.hawkbit.repository.ControllerManagement;
+import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
+import org.eclipse.hawkbit.repository.model.LocalArtifact;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.AmqpRejectAndDontRequeueException;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.core.MessageProperties;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.cache.Cache;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.authentication.AuthenticationServiceException;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.CredentialsExpiredException;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.util.UriComponentsBuilder;
+
+/**
+ *
+ * {@link AmqpMessageHandlerService} handles all incoming target authentication
+ * AMQP messages that can be used by 3rd party CDN services to check if a target
+ * is permitted to download certain artifact. This is handled by the queue that
+ * is configured for the property
+ * hawkbit.dmf.rabbitmq.authenticationReceiverQueue.
+ *
+ */
+public class AmqpAuthenticationMessageHandler extends BaseAmqpService {
+ private static final Logger LOG = LoggerFactory.getLogger(AmqpAuthenticationMessageHandler.class);
+
+ private final AmqpControllerAuthentication authenticationManager;
+
+ private final ArtifactManagement artifactManagement;
+
+ private final Cache cache;
+
+ private final HostnameResolver hostnameResolver;
+
+ private final ControllerManagement controllerManagement;
+
+ /**
+ * @param rabbitTemplate
+ * the configured amqp template.
+ * @param artifactManagement
+ * for artifact URI generation
+ * @param cache
+ * for download Ids
+ * @param hostnameResolver
+ * for resolving the host for downloads
+ * @param authenticationManager
+ * for target authentication
+ * @param controllerManagement
+ * for target repo access
+ */
+ public AmqpAuthenticationMessageHandler(final RabbitTemplate rabbitTemplate,
+ final AmqpControllerAuthentication authenticationManager, final ArtifactManagement artifactManagement,
+ final Cache cache, final HostnameResolver hostnameResolver,
+ final ControllerManagement controllerManagement) {
+ super(rabbitTemplate);
+ this.authenticationManager = authenticationManager;
+ this.artifactManagement = artifactManagement;
+ this.cache = cache;
+ this.hostnameResolver = hostnameResolver;
+ this.controllerManagement = controllerManagement;
+ }
+
+ /**
+ * Executed on a authentication request.
+ *
+ * @param message
+ * the amqp message
+ * @return the rpc message back to supplier.
+ */
+ @RabbitListener(queues = "${hawkbit.dmf.rabbitmq.authenticationReceiverQueue}", containerFactory = "listenerContainerFactory")
+ public Message onAuthenticationRequest(final Message message) {
+ checkContentTypeJson(message);
+ final SecurityContext oldContext = SecurityContextHolder.getContext();
+ try {
+ return handleAuthenticationMessage(message);
+ } catch (final RuntimeException ex) {
+ throw new AmqpRejectAndDontRequeueException(ex);
+ } finally {
+ SecurityContextHolder.setContext(oldContext);
+ }
+ }
+
+ /**
+ * check action for this download purposes, the method will throw an
+ * EntityNotFoundException in case the controller is not allowed to download
+ * this file because it's not assigned to an action and not assigned to this
+ * controller. Otherwise no controllerId is set = anonymous download
+ *
+ * @param secruityToken
+ * the security token which holds the target ID to check on
+ * @param localArtifact
+ * the local artifact to verify if the given target is allowed to
+ * download this artifact
+ */
+ private void checkIfArtifactIsAssignedToTarget(final TenantSecurityToken secruityToken,
+ final LocalArtifact localArtifact) {
+
+ if (secruityToken.getControllerId() != null) {
+ checkByControllerId(localArtifact, secruityToken.getControllerId());
+ } else if (secruityToken.getTargetId() != null) {
+ checkByTargetId(localArtifact, secruityToken.getTargetId());
+ } else {
+ LOG.info("anonymous download no authentication check for artifact {}", localArtifact);
+ return;
+ }
+
+ }
+
+ private void checkByTargetId(final LocalArtifact localArtifact, final Long targetId) {
+ LOG.debug("no anonymous download request, doing authentication check for target {} and artifact {}", targetId,
+ localArtifact);
+ if (!controllerManagement.hasTargetArtifactAssigned(targetId, localArtifact)) {
+ LOG.info("target {} tried to download artifact {} which is not assigned to the target", targetId,
+ localArtifact);
+ throw new EntityNotFoundException();
+ }
+ LOG.info("download security check for target {} and artifact {} granted", targetId, localArtifact);
+ }
+
+ private void checkByControllerId(final LocalArtifact localArtifact, final String controllerId) {
+ LOG.debug("no anonymous download request, doing authentication check for target {} and artifact {}",
+ controllerId, localArtifact);
+ if (!controllerManagement.hasTargetArtifactAssigned(controllerId, localArtifact)) {
+ LOG.info("target {} tried to download artifact {} which is not assigned to the target", controllerId,
+ localArtifact);
+ throw new EntityNotFoundException();
+ }
+ LOG.info("download security check for target {} and artifact {} granted", controllerId, localArtifact);
+ }
+
+ private LocalArtifact findLocalArtifactByFileResource(final FileResource fileResource) {
+ if (fileResource.getSha1() != null) {
+ return artifactManagement.findFirstLocalArtifactsBySHA1(fileResource.getSha1());
+ } else if (fileResource.getFilename() != null) {
+ return artifactManagement.findLocalArtifactByFilename(fileResource.getFilename()).stream().findFirst()
+ .orElse(null);
+ } else if (fileResource.getArtifactId() != null) {
+ return artifactManagement.findLocalArtifact(fileResource.getArtifactId());
+ } else if (fileResource.getSoftwareModuleFilenameResource() != null) {
+ return artifactManagement
+ .findByFilenameAndSoftwareModule(fileResource.getSoftwareModuleFilenameResource().getFilename(),
+ fileResource.getSoftwareModuleFilenameResource().getSoftwareModuleId())
+ .stream().findFirst().orElse(null);
+ }
+ return null;
+ }
+
+ private static Artifact convertDbArtifact(final DbArtifact dbArtifact) {
+ final Artifact artifact = new Artifact();
+ artifact.setSize(dbArtifact.getSize());
+ final DbArtifactHash dbArtifactHash = dbArtifact.getHashes();
+ artifact.setHashes(new ArtifactHash(dbArtifactHash.getSha1(), dbArtifactHash.getMd5()));
+ return artifact;
+ }
+
+ private Message handleAuthenticationMessage(final Message message) {
+ final DownloadResponse authentificationResponse = new DownloadResponse();
+ final MessageProperties messageProperties = message.getMessageProperties();
+ final TenantSecurityToken secruityToken = convertMessage(message, TenantSecurityToken.class);
+
+ final FileResource fileResource = secruityToken.getFileResource();
+ try {
+ SecurityContextHolder.getContext().setAuthentication(authenticationManager.doAuthenticate(secruityToken));
+
+ final LocalArtifact localArtifact = findLocalArtifactByFileResource(fileResource);
+
+ if (localArtifact == null) {
+ LOG.info("target {} requested file resource {} which does not exists to download",
+ secruityToken.getControllerId(), fileResource);
+ throw new EntityNotFoundException();
+ }
+
+ checkIfArtifactIsAssignedToTarget(secruityToken, localArtifact);
+
+ final Artifact artifact = convertDbArtifact(artifactManagement.loadLocalArtifactBinary(localArtifact));
+ if (artifact == null) {
+ throw new EntityNotFoundException();
+ }
+ authentificationResponse.setArtifact(artifact);
+ final String downloadId = UUID.randomUUID().toString();
+ // SHA1 key is set, download by SHA1
+ final DownloadArtifactCache downloadCache = new DownloadArtifactCache(DownloadType.BY_SHA1,
+ localArtifact.getSha1Hash());
+ cache.put(downloadId, downloadCache);
+ authentificationResponse
+ .setDownloadUrl(UriComponentsBuilder.fromUri(hostnameResolver.resolveHostname().toURI())
+ .path("/api/v1/downloadserver/downloadId/").path(downloadId).build().toUriString());
+ authentificationResponse.setResponseCode(HttpStatus.OK.value());
+ } catch (final BadCredentialsException | AuthenticationServiceException | CredentialsExpiredException e) {
+ LOG.error("Login failed", e);
+ authentificationResponse.setResponseCode(HttpStatus.FORBIDDEN.value());
+ authentificationResponse.setMessage("Login failed");
+ } catch (final URISyntaxException e) {
+ LOG.error("URI build exception", e);
+ authentificationResponse.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
+ authentificationResponse.setMessage("Building download URI failed");
+ } catch (final EntityNotFoundException e) {
+ final String errorMessage = "Artifact for resource " + fileResource + "not found ";
+ LOG.warn(errorMessage, e);
+ authentificationResponse.setResponseCode(HttpStatus.NOT_FOUND.value());
+ authentificationResponse.setMessage(errorMessage);
+ }
+
+ return getMessageConverter().toMessage(authentificationResponse, messageProperties);
+ }
+
+}
diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java
index 09edd41d3..24a5025a2 100644
--- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java
+++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java
@@ -9,14 +9,18 @@
package org.eclipse.hawkbit.amqp;
import java.time.Duration;
-import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
+import org.eclipse.hawkbit.api.HostnameResolver;
+import org.eclipse.hawkbit.cache.CacheConstants;
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
+import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
+import org.eclipse.hawkbit.repository.EntityFactory;
+import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.security.DdiSecurityProperties;
import org.eclipse.hawkbit.security.SystemSecurityContext;
@@ -41,14 +45,17 @@ import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cache.Cache;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.ErrorHandler;
+import com.google.common.collect.Maps;
+
/**
- * Spring configuration for AMQP 0.9 based DMF communication for indirect device
+ * Spring configuration for AMQP based DMF communication for indirect device
* integration.
*
*/
@@ -251,17 +258,51 @@ public class AmqpConfiguration {
}
/**
- * Create amqp handler service bean.
+ * Create AMQP handler service bean.
*
+ * @param rabbitTemplate
+ * for converting messages
* @param amqpMessageDispatcherService
* to sending events to DMF client
+ * @param controllerManagement
+ * for target repo access
+ * @param entityFactory
+ * to create entities
*
* @return handler service bean
*/
@Bean
- public AmqpMessageHandlerService amqpMessageHandlerService(
- final AmqpMessageDispatcherService amqpMessageDispatcherService) {
- return new AmqpMessageHandlerService(rabbitTemplate(), amqpMessageDispatcherService);
+ public AmqpMessageHandlerService amqpMessageHandlerService(final RabbitTemplate rabbitTemplate,
+ final AmqpMessageDispatcherService amqpMessageDispatcherService,
+ final ControllerManagement controllerManagement, final EntityFactory entityFactory) {
+ return new AmqpMessageHandlerService(rabbitTemplate, amqpMessageDispatcherService, controllerManagement,
+ entityFactory);
+ }
+
+ /**
+ * Create AMQP handler service bean for authentication messages.
+ *
+ * @param rabbitTemplate
+ * for converting messages
+ * @param authenticationManager
+ * for target authentication
+ * @param artifactManagement
+ * for artifact URI generation
+ * @param cache
+ * for download IDs
+ * @param hostnameResolver
+ * for resolving the host for downloads
+ * @param controllerManagement
+ * for target repo access
+ * @return handler service bean
+ */
+ @Bean
+ public AmqpAuthenticationMessageHandler amqpAuthenticationMessageHandler(final RabbitTemplate rabbitTemplate,
+ final AmqpControllerAuthentication authenticationManager, final ArtifactManagement artifactManagement,
+ @Qualifier(CacheConstants.DOWNLOAD_ID_CACHE) final Cache cache, final HostnameResolver hostnameResolver,
+ final ControllerManagement controllerManagement) {
+ return new AmqpAuthenticationMessageHandler(rabbitTemplate, authenticationManager, artifactManagement, cache,
+ hostnameResolver, controllerManagement);
}
/**
@@ -291,22 +332,25 @@ public class AmqpConfiguration {
@Bean
@ConditionalOnMissingBean(AmqpControllerAuthentication.class)
- public AmqpControllerAuthentication amqpControllerAuthentication(final ControllerManagement controllerManagement,
+ public AmqpControllerAuthentication amqpControllerAuthentication(final SystemManagement systemManagement,
+ final ControllerManagement controllerManagement,
final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
final DdiSecurityProperties ddiSecruityProperties, final SystemSecurityContext systemSecurityContext) {
- return new AmqpControllerAuthentication(controllerManagement, tenantConfigurationManagement, tenantAware,
- ddiSecruityProperties, systemSecurityContext);
+ return new AmqpControllerAuthentication(systemManagement, controllerManagement, tenantConfigurationManagement,
+ tenantAware, ddiSecruityProperties, systemSecurityContext);
}
@Bean
@ConditionalOnMissingBean(AmqpMessageDispatcherService.class)
public AmqpMessageDispatcherService amqpMessageDispatcherService(final RabbitTemplate rabbitTemplate,
- final AmqpSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler) {
- return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler);
+ final AmqpSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
+ final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement) {
+ return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler,
+ systemSecurityContext, systemManagement);
}
private static Map getTTLMaxArgsAuthenticationQueue() {
- final Map args = new HashMap<>();
+ final Map args = Maps.newHashMapWithExpectedSize(2);
args.put("x-message-ttl", Duration.ofSeconds(30).toMillis());
args.put("x-max-length", 1_000);
return args;
diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentication.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentication.java
index 2e604aad1..64abd2778 100644
--- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentication.java
+++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentication.java
@@ -8,7 +8,6 @@
*/
package org.eclipse.hawkbit.amqp;
-import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
@@ -16,6 +15,7 @@ import javax.annotation.PostConstruct;
import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.repository.ControllerManagement;
+import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.security.ControllerPreAuthenticateSecurityTokenFilter;
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedAnonymousDownload;
@@ -32,6 +32,8 @@ import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
+import com.google.common.collect.Lists;
+
/**
*
* A controller which handles the DMF AMQP authentication.
@@ -42,10 +44,12 @@ public class AmqpControllerAuthentication {
private final PreAuthTokenSourceTrustAuthenticationProvider preAuthenticatedAuthenticationProvider = new PreAuthTokenSourceTrustAuthenticationProvider();
- private final List filterChain = new ArrayList<>();
+ private List filterChain;
private final ControllerManagement controllerManagement;
+ private final SystemManagement systemManagement;
+
private final TenantConfigurationManagement tenantConfigurationManagement;
private final TenantAware tenantAware;
@@ -57,6 +61,7 @@ public class AmqpControllerAuthentication {
/**
* Constructor.
*
+ * @param systemManagement
* @param controllerManagement
* @param tenantConfigurationManagement
* @param tenantAware
@@ -66,10 +71,12 @@ public class AmqpControllerAuthentication {
* @param systemSecurityContext
* security context
*/
- public AmqpControllerAuthentication(final ControllerManagement controllerManagement,
+ public AmqpControllerAuthentication(final SystemManagement systemManagement,
+ final ControllerManagement controllerManagement,
final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
final DdiSecurityProperties ddiSecruityProperties, final SystemSecurityContext systemSecurityContext) {
this.controllerManagement = controllerManagement;
+ this.systemManagement = systemManagement;
this.tenantConfigurationManagement = tenantConfigurationManagement;
this.tenantAware = tenantAware;
this.ddiSecruityProperties = ddiSecruityProperties;
@@ -85,6 +92,8 @@ public class AmqpControllerAuthentication {
}
private void addFilter() {
+ filterChain = Lists.newArrayListWithExpectedSize(5);
+
final ControllerPreAuthenticatedGatewaySecurityTokenFilter gatewaySecurityTokenFilter = new ControllerPreAuthenticatedGatewaySecurityTokenFilter(
tenantConfigurationManagement, tenantAware, systemSecurityContext);
filterChain.add(gatewaySecurityTokenFilter);
@@ -106,13 +115,15 @@ public class AmqpControllerAuthentication {
}
/**
- * Performs authentication with the secruity token.
+ * Performs authentication with the security token.
*
* @param secruityToken
* the authentication request object
- * @return the authentfication object
+ * @return the authentication object
*/
public Authentication doAuthenticate(final TenantSecurityToken secruityToken) {
+ resolveTenant(secruityToken);
+
PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(null, null);
for (final PreAuthentificationFilter filter : filterChain) {
final PreAuthenticatedAuthenticationToken authenticationRest = createAuthentication(filter, secruityToken);
@@ -126,6 +137,14 @@ public class AmqpControllerAuthentication {
}
+ private void resolveTenant(final TenantSecurityToken securityToken) {
+ if (securityToken.getTenant() == null) {
+ securityToken.setTenant(systemSecurityContext
+ .runAsSystem(() -> systemManagement.getTenantMetadata(securityToken.getTenantId()).getTenant()));
+ }
+
+ }
+
private static PreAuthenticatedAuthenticationToken createAuthentication(final PreAuthentificationFilter filter,
final TenantSecurityToken secruityToken) {
diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpDeadletterProperties.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpDeadletterProperties.java
index 7ed5e90c1..5a7e3e083 100644
--- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpDeadletterProperties.java
+++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpDeadletterProperties.java
@@ -9,24 +9,26 @@
package org.eclipse.hawkbit.amqp;
import java.time.Duration;
-import java.util.HashMap;
import java.util.Map;
import org.springframework.amqp.core.Queue;
import org.springframework.boot.context.properties.ConfigurationProperties;
+import com.google.common.collect.Maps;
+
/**
* Bean which holds the necessary properties for configuring the AMQP deadletter
* queue.
*/
@ConfigurationProperties("hawkbit.dmf.rabbitmq.deadLetter")
public class AmqpDeadletterProperties {
+ private static final int THREE_WEEKS = 21;
/**
* Message time to live (ttl) for the deadletter queue. Default ttl is 3
* weeks.
*/
- private long ttl = Duration.ofDays(21).toMillis();
+ private long ttl = Duration.ofDays(THREE_WEEKS).toMillis();
/**
* Return the deadletter arguments.
@@ -36,7 +38,7 @@ public class AmqpDeadletterProperties {
* @return map which holds the properties
*/
public Map getDeadLetterExchangeArgs(final String exchange) {
- final Map args = new HashMap<>();
+ final Map args = Maps.newHashMapWithExpectedSize(1);
args.put("x-dead-letter-exchange", exchange);
return args;
}
@@ -53,7 +55,7 @@ public class AmqpDeadletterProperties {
}
private Map getTTLArgs() {
- final Map args = new HashMap<>();
+ final Map args = Maps.newHashMapWithExpectedSize(1);
args.put("x-message-ttl", getTtl());
return args;
}
diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java
index 1d24d5846..a4ea97e72 100644
--- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java
+++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java
@@ -14,8 +14,10 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
+import org.eclipse.hawkbit.api.ApiType;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
-import org.eclipse.hawkbit.api.UrlProtocol;
+import org.eclipse.hawkbit.api.URLPlaceholder;
+import org.eclipse.hawkbit.api.URLPlaceholder.SoftwareData;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
@@ -25,8 +27,11 @@ import org.eclipse.hawkbit.dmf.json.model.DownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.SoftwareModule;
import org.eclipse.hawkbit.eventbus.EventSubscriber;
import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent;
+import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
+import org.eclipse.hawkbit.repository.model.Target;
+import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.util.IpUtil;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
@@ -47,6 +52,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
private final ArtifactUrlHandler artifactUrlHandler;
private final AmqpSenderService amqpSenderService;
+ private final SystemSecurityContext systemSecurityContext;
+ private final SystemManagement systemManagement;
/**
* Constructor.
@@ -57,12 +64,19 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
* to send AMQP message
* @param artifactUrlHandler
* for generating download URLs
+ * @param systemSecurityContext
+ * for execution with system permissions
+ * @param systemManagement
+ * to access to tenant metadata
*/
public AmqpMessageDispatcherService(final RabbitTemplate rabbitTemplate, final AmqpSenderService amqpSenderService,
- final ArtifactUrlHandler artifactUrlHandler) {
+ final ArtifactUrlHandler artifactUrlHandler, final SystemSecurityContext systemSecurityContext,
+ final SystemManagement systemManagement) {
super(rabbitTemplate);
this.artifactUrlHandler = artifactUrlHandler;
this.amqpSenderService = amqpSenderService;
+ this.systemSecurityContext = systemSecurityContext;
+ this.systemManagement = systemManagement;
}
/**
@@ -74,20 +88,24 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
*/
@Subscribe
public void targetAssignDistributionSet(final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent) {
- final URI targetAdress = targetAssignDistributionSetEvent.getTargetAdress();
+ final URI targetAdress = targetAssignDistributionSetEvent.getTarget().getTargetInfo().getAddress();
if (!IpUtil.isAmqpUri(targetAdress)) {
return;
}
- final String controllerId = targetAssignDistributionSetEvent.getControllerId();
+ final String controllerId = targetAssignDistributionSetEvent.getTarget().getControllerId();
final Collection modules = targetAssignDistributionSetEvent
.getSoftwareModules();
final DownloadAndUpdateRequest downloadAndUpdateRequest = new DownloadAndUpdateRequest();
downloadAndUpdateRequest.setActionId(targetAssignDistributionSetEvent.getActionId());
- downloadAndUpdateRequest.setTargetSecurityToken(targetAssignDistributionSetEvent.getTargetToken());
+
+ final String targetSecurityToken = systemSecurityContext
+ .runAsSystem(targetAssignDistributionSetEvent.getTarget()::getSecurityToken);
+ downloadAndUpdateRequest.setTargetSecurityToken(targetSecurityToken);
for (final org.eclipse.hawkbit.repository.model.SoftwareModule softwareModule : modules) {
- final SoftwareModule amqpSoftwareModule = convertToAmqpSoftwareModule(controllerId, softwareModule);
+ final SoftwareModule amqpSoftwareModule = convertToAmqpSoftwareModule(
+ targetAssignDistributionSetEvent.getTarget(), softwareModule);
downloadAndUpdateRequest.addSoftwareModule(amqpSoftwareModule);
}
@@ -133,51 +151,42 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
return messageProperties;
}
- private SoftwareModule convertToAmqpSoftwareModule(final String targetId,
+ private SoftwareModule convertToAmqpSoftwareModule(final Target target,
final org.eclipse.hawkbit.repository.model.SoftwareModule softwareModule) {
final SoftwareModule amqpSoftwareModule = new SoftwareModule();
amqpSoftwareModule.setModuleId(softwareModule.getId());
amqpSoftwareModule.setModuleType(softwareModule.getType().getKey());
amqpSoftwareModule.setModuleVersion(softwareModule.getVersion());
- final List artifacts = convertArtifacts(targetId, softwareModule.getLocalArtifacts());
+ final List artifacts = convertArtifacts(target, softwareModule.getLocalArtifacts());
amqpSoftwareModule.setArtifacts(artifacts);
return amqpSoftwareModule;
}
- private List convertArtifacts(final String targetId, final List localArtifacts) {
+ private List convertArtifacts(final Target target, final List localArtifacts) {
if (localArtifacts.isEmpty()) {
return Collections.emptyList();
}
- return localArtifacts.stream().map(localArtifact -> convertArtifact(targetId, localArtifact))
+ return localArtifacts.stream().map(localArtifact -> convertArtifact(target, localArtifact))
.collect(Collectors.toList());
}
- private Artifact convertArtifact(final String targetId, final LocalArtifact localArtifact) {
+ private Artifact convertArtifact(final Target target, final LocalArtifact localArtifact) {
final Artifact artifact = new Artifact();
- if (artifactUrlHandler.protocolSupported(UrlProtocol.COAP)) {
- artifact.getUrls().put(Artifact.UrlProtocol.COAP,
- artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(),
- localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.COAP));
- }
-
- if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTP)) {
- artifact.getUrls().put(Artifact.UrlProtocol.HTTP,
- artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(),
- localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTP));
- }
-
- if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTPS)) {
- artifact.getUrls().put(Artifact.UrlProtocol.HTTPS,
- artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(),
- localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTPS));
- }
+ artifact.setUrls(artifactUrlHandler
+ .getUrls(new URLPlaceholder(systemManagement.getTenantMetadata().getTenant(),
+ systemManagement.getTenantMetadata().getId(), target.getControllerId(), target.getId(),
+ new SoftwareData(localArtifact.getSoftwareModule().getId(), localArtifact.getFilename(),
+ localArtifact.getId(), localArtifact.getSha1Hash())),
+ ApiType.DMF)
+ .stream().collect(Collectors.toMap(e -> e.getProtocol(), e -> e.getRef())));
artifact.setFilename(localArtifact.getFilename());
artifact.setHashes(new ArtifactHash(localArtifact.getSha1Hash(), localArtifact.getMd5Hash()));
artifact.setSize(localArtifact.getSize());
return artifact;
}
+
}
diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java
index e8387e0c2..56ecc84cb 100644
--- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java
+++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java
@@ -9,7 +9,6 @@
package org.eclipse.hawkbit.amqp;
import java.net.URI;
-import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
@@ -18,68 +17,45 @@ import java.util.UUID;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
-import org.eclipse.hawkbit.api.HostnameResolver;
-import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
-import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
-import org.eclipse.hawkbit.cache.CacheConstants;
-import org.eclipse.hawkbit.cache.DownloadArtifactCache;
-import org.eclipse.hawkbit.cache.DownloadType;
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.ActionUpdateStatus;
-import org.eclipse.hawkbit.dmf.json.model.Artifact;
-import org.eclipse.hawkbit.dmf.json.model.ArtifactHash;
-import org.eclipse.hawkbit.dmf.json.model.DownloadResponse;
-import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
-import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource;
import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
-import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent;
-import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
import org.eclipse.hawkbit.repository.exception.TooManyStatusEntriesException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.DistributionSet;
-import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
-import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.util.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
import org.springframework.amqp.core.Message;
-import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.cache.Cache;
-import org.springframework.http.HttpStatus;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
-import org.springframework.security.authentication.AuthenticationServiceException;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
-import org.springframework.web.util.UriComponentsBuilder;
/**
*
- * {@link AmqpMessageHandlerService} handles all incoming AMQP messages for the
- * queue which is configure for the property hawkbit.dmf.rabbitmq.receiverQueue.
+ * {@link AmqpMessageHandlerService} handles all incoming target interaction
+ * AMQP messages (e.g. create target, check for updates etc.) for the queue
+ * which is configured for the property hawkbit.dmf.rabbitmq.receiverQueue.
*
*/
public class AmqpMessageHandlerService extends BaseAmqpService {
@@ -88,40 +64,29 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
private final AmqpMessageDispatcherService amqpMessageDispatcherService;
- @Autowired
- private ControllerManagement controllerManagement;
+ private final ControllerManagement controllerManagement;
- @Autowired
- private AmqpControllerAuthentication authenticationManager;
-
- @Autowired
- private ArtifactManagement artifactManagement;
-
- @Autowired
- @Qualifier(CacheConstants.DOWNLOAD_ID_CACHE)
- private Cache cache;
-
- @Autowired
- private HostnameResolver hostnameResolver;
-
- @Autowired
- private EntityFactory entityFactory;
-
- @Autowired
- private SystemSecurityContext systemSecurityContext;
+ private final EntityFactory entityFactory;
/**
* Constructor.
*
- * @param defaultTemplate
- * the configured amqp template.
+ * @param rabbitTemplate
+ * for converting messages
* @param amqpMessageDispatcherService
* to sending events to DMF client
+ * @param controllerManagement
+ * for target repo access
+ * @param entityFactory
+ * to create entities
*/
- public AmqpMessageHandlerService(final RabbitTemplate defaultTemplate,
- final AmqpMessageDispatcherService amqpMessageDispatcherService) {
- super(defaultTemplate);
+ public AmqpMessageHandlerService(final RabbitTemplate rabbitTemplate,
+ final AmqpMessageDispatcherService amqpMessageDispatcherService,
+ final ControllerManagement controllerManagement, final EntityFactory entityFactory) {
+ super(rabbitTemplate);
this.amqpMessageDispatcherService = amqpMessageDispatcherService;
+ this.controllerManagement = controllerManagement;
+ this.entityFactory = entityFactory;
}
/**
@@ -142,28 +107,6 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
return onMessage(message, type, tenant, getRabbitTemplate().getConnectionFactory().getVirtualHost());
}
- /**
- * Executed on a authentication request.
- *
- * @param message
- * the amqp message
- * @return the rpc message back to supplier.
- */
- @RabbitListener(queues = "${hawkbit.dmf.rabbitmq.authenticationReceiverQueue}", containerFactory = "listenerContainerFactory")
- public Message onAuthenticationRequest(final Message message) {
- checkContentTypeJson(message);
- final SecurityContext oldContext = SecurityContextHolder.getContext();
- try {
- return handleAuthentifiactionMessage(message);
- } catch (final IllegalArgumentException ex) {
- throw new AmqpRejectAndDontRequeueException("Invalid message!", ex);
- } catch (final TenantNotExistException | TooManyStatusEntriesException e) {
- throw new AmqpRejectAndDontRequeueException(e);
- } finally {
- SecurityContextHolder.setContext(oldContext);
- }
- }
-
/**
* * Executed if a amqp message arrives.
*
@@ -206,108 +149,6 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
return null;
}
- private Message handleAuthentifiactionMessage(final Message message) {
- final DownloadResponse authentificationResponse = new DownloadResponse();
- final MessageProperties messageProperties = message.getMessageProperties();
- final TenantSecurityToken secruityToken = convertMessage(message, TenantSecurityToken.class);
- final FileResource fileResource = secruityToken.getFileResource();
- try {
- SecurityContextHolder.getContext().setAuthentication(authenticationManager.doAuthenticate(secruityToken));
-
- final LocalArtifact localArtifact = findLocalArtifactByFileResource(fileResource);
-
- if (localArtifact == null) {
- LOG.info("target {} requested file resource {} which does not exists to download",
- secruityToken.getControllerId(), fileResource);
- throw new EntityNotFoundException();
- }
-
- checkIfArtifactIsAssignedToTarget(secruityToken, localArtifact);
-
- final Artifact artifact = convertDbArtifact(artifactManagement.loadLocalArtifactBinary(localArtifact));
- if (artifact == null) {
- throw new EntityNotFoundException();
- }
- authentificationResponse.setArtifact(artifact);
- final String downloadId = UUID.randomUUID().toString();
- // SHA1 key is set, download by SHA1
- final DownloadArtifactCache downloadCache = new DownloadArtifactCache(DownloadType.BY_SHA1,
- localArtifact.getSha1Hash());
- cache.put(downloadId, downloadCache);
- authentificationResponse
- .setDownloadUrl(UriComponentsBuilder.fromUri(hostnameResolver.resolveHostname().toURI())
- .path("/api/v1/downloadserver/downloadId/").path(downloadId).build().toUriString());
- authentificationResponse.setResponseCode(HttpStatus.OK.value());
- } catch (final BadCredentialsException | AuthenticationServiceException | CredentialsExpiredException e) {
- LOG.error("Login failed", e);
- authentificationResponse.setResponseCode(HttpStatus.FORBIDDEN.value());
- authentificationResponse.setMessage("Login failed");
- } catch (final URISyntaxException e) {
- LOG.error("URI build exception", e);
- authentificationResponse.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
- authentificationResponse.setMessage("Building download URI failed");
- } catch (final EntityNotFoundException e) {
- final String errorMessage = "Artifact for resource " + fileResource + "not found ";
- LOG.warn(errorMessage, e);
- authentificationResponse.setResponseCode(HttpStatus.NOT_FOUND.value());
- authentificationResponse.setMessage(errorMessage);
- }
-
- return getMessageConverter().toMessage(authentificationResponse, messageProperties);
- }
-
- /**
- * check action for this download purposes, the method will throw an
- * EntityNotFoundException in case the controller is not allowed to download
- * this file because it's not assigned to an action and not assigned to this
- * controller. Otherwise no controllerId is set = anonymous download
- *
- * @param secruityToken
- * the security token which holds the target ID to check on
- * @param localArtifact
- * the local artifact to verify if the given target is allowed to
- * download this artifact
- */
- private void checkIfArtifactIsAssignedToTarget(final TenantSecurityToken secruityToken,
- final LocalArtifact localArtifact) {
- final String controllerId = secruityToken.getControllerId();
- if (controllerId == null) {
- LOG.info("anonymous download no authentication check for artifact {}", localArtifact);
- return;
- }
- LOG.debug("no anonymous download request, doing authentication check for target {} and artifact {}",
- controllerId, localArtifact);
- if (!controllerManagement.hasTargetArtifactAssigned(controllerId, localArtifact)) {
- LOG.info("target {} tried to download artifact {} which is not assigned to the target", controllerId,
- localArtifact);
- throw new EntityNotFoundException();
- }
- LOG.info("download security check for target {} and artifact {} granted", controllerId, localArtifact);
- }
-
- private LocalArtifact findLocalArtifactByFileResource(final FileResource fileResource) {
- if (fileResource.getSha1() != null) {
- return artifactManagement.findFirstLocalArtifactsBySHA1(fileResource.getSha1());
- } else if (fileResource.getFilename() != null) {
- return artifactManagement.findLocalArtifactByFilename(fileResource.getFilename()).stream().findFirst()
- .orElse(null);
- } else if (fileResource.getSoftwareModuleFilenameResource() != null) {
- return artifactManagement
- .findByFilenameAndSoftwareModule(fileResource.getSoftwareModuleFilenameResource().getFilename(),
- fileResource.getSoftwareModuleFilenameResource().getSoftwareModuleId())
- .stream().findFirst().orElse(null);
- }
- return null;
- }
-
- private static Artifact convertDbArtifact(final DbArtifact dbArtifact) {
- final Artifact artifact = new Artifact();
- artifact.setSize(dbArtifact.getSize());
- final DbArtifactHash dbArtifactHash = dbArtifact.getHashes();
- artifact.setHashes(new ArtifactHash(dbArtifactHash.getSha1(), dbArtifactHash.getMd5()));
- return artifact;
- }
-
private static void setSecurityContext(final Authentication authentication) {
final SecurityContextImpl securityContextImpl = new SecurityContextImpl();
securityContextImpl.setAuthentication(authentication);
@@ -361,10 +202,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
final DistributionSet distributionSet = action.get().getDistributionSet();
final List softwareModuleList = controllerManagement
.findSoftwareModulesByDistributionSet(distributionSet);
- final String targetSecurityToken = systemSecurityContext.runAsSystem(() -> target.getSecurityToken());
amqpMessageDispatcherService.targetAssignDistributionSet(new TargetAssignDistributionSetEvent(
- target.getOptLockRevision(), target.getTenant(), target.getControllerId(), action.get().getId(),
- softwareModuleList, target.getTargetInfo().getAddress(), targetSecurityToken));
+ target.getOptLockRevision(), target.getTenant(), target, action.get().getId(), softwareModuleList));
}
@@ -481,7 +320,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
return action;
}
- private void handleCancelRejected(final Message message, final Action action, final ActionStatus actionStatus) {
+ private static void handleCancelRejected(final Message message, final Action action,
+ final ActionStatus actionStatus) {
if (action.isCancelingOrCanceled()) {
actionStatus.setStatus(Status.WARNING);
@@ -495,39 +335,4 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
}
}
- private static void checkContentTypeJson(final Message message) {
- final MessageProperties messageProperties = message.getMessageProperties();
- if (messageProperties.getContentType() != null && messageProperties.getContentType().contains("json")) {
- return;
- }
- throw new AmqpRejectAndDontRequeueException("Content-Type is not JSON compatible");
- }
-
- void setControllerManagement(final ControllerManagement controllerManagement) {
- this.controllerManagement = controllerManagement;
- }
-
- void setHostnameResolver(final HostnameResolver hostnameResolver) {
- this.hostnameResolver = hostnameResolver;
- }
-
- void setAuthenticationManager(final AmqpControllerAuthentication authenticationManager) {
- this.authenticationManager = authenticationManager;
- }
-
- void setArtifactManagement(final ArtifactManagement artifactManagement) {
- this.artifactManagement = artifactManagement;
- }
-
- void setCache(final Cache cache) {
- this.cache = cache;
- }
-
- void setEntityFactory(final EntityFactory entityFactory) {
- this.entityFactory = entityFactory;
- }
-
- void setSystemSecurityContext(final SystemSecurityContext systemSecurityContext) {
- this.systemSecurityContext = systemSecurityContext;
- }
}
diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java
index b90f8ca46..dd80262a5 100644
--- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java
+++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java
@@ -20,6 +20,16 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("hawkbit.dmf.rabbitmq")
public class AmqpProperties {
+ private static final int ONE_MINUTE = 60;
+
+ private static final int DEFAULT_QUEUE_DECLARATION_RETRIES = 50;
+
+ private static final int DEFAULT_INITIAL_CONSUMERS = 3;
+
+ private static final int DEFAULT_PREFETCH_COUNT = 10;
+
+ private static final int DEFAULT_MAX_CONSUMERS = 10;
+
/**
* Enable DMF API based on AMQP 0.9
*/
@@ -54,24 +64,24 @@ public class AmqpProperties {
/**
* Requested heartbeat interval from broker in {@link TimeUnit#SECONDS}.
*/
- private int requestedHeartBeat = (int) TimeUnit.SECONDS.toSeconds(60);
+ private int requestedHeartBeat = (int) TimeUnit.SECONDS.toSeconds(ONE_MINUTE);
/**
* Sets an upper limit to the number of consumers.
*/
- private int maxConcurrentConsumers = 10;
+ private int maxConcurrentConsumers = DEFAULT_MAX_CONSUMERS;
/**
* Tells the broker how many messages to send to each consumer in a single
* request. Often this can be set quite high to improve throughput.
*/
- private int prefetchCount = 10;
+ private int prefetchCount = DEFAULT_PREFETCH_COUNT;
/**
* Initial number of consumers. Is scaled up if necessary up to
* {@link #maxConcurrentConsumers}.
*/
- private int initialConcurrentConsumers = 3;
+ private int initialConcurrentConsumers = DEFAULT_INITIAL_CONSUMERS;
/**
* The number of retry attempts when passive queue declaration fails.
@@ -79,7 +89,7 @@ public class AmqpProperties {
* consuming from multiple queues, when not all queues were available during
* initialization.
*/
- private int declarationRetries = 50;
+ private int declarationRetries = DEFAULT_QUEUE_DECLARATION_RETRIES;
public int getDeclarationRetries() {
return declarationRetries;
diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java
index b11d5a437..b0bd1f962 100644
--- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java
+++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java
@@ -17,6 +17,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
import org.springframework.amqp.core.Message;
+import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.AbstractJavaTypeMapper;
import org.springframework.amqp.support.converter.MessageConverter;
@@ -39,6 +40,14 @@ public class BaseAmqpService {
this.rabbitTemplate = rabbitTemplate;
}
+ protected static void checkContentTypeJson(final Message message) {
+ final MessageProperties messageProperties = message.getMessageProperties();
+ if (messageProperties.getContentType() != null && messageProperties.getContentType().contains("json")) {
+ return;
+ }
+ throw new AmqpRejectAndDontRequeueException("Content-Type is not JSON compatible");
+ }
+
/**
* Is needed to convert a incoming message to is originally object type.
*
@@ -98,7 +107,7 @@ public class BaseAmqpService {
return value.toString();
}
- protected final void logAndThrowMessageError(final Message message, final String error) {
+ protected static final void logAndThrowMessageError(final Message message, final String error) {
LOGGER.warn("Warning! \"{}\" reported by message: {}", error, message);
throw new AmqpRejectAndDontRequeueException(error);
}
diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java
index 9c1265960..c2ac1c35b 100644
--- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java
+++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java
@@ -16,6 +16,11 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import java.net.URL;
+
+import org.eclipse.hawkbit.api.HostnameResolver;
+import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
+import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.DownloadResponse;
@@ -23,8 +28,16 @@ import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
+import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
+import org.eclipse.hawkbit.repository.jpa.JpaEntityFactory;
+import org.eclipse.hawkbit.repository.jpa.model.JpaLocalArtifact;
+import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
+import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
+import org.eclipse.hawkbit.repository.model.LocalArtifact;
+import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
+import org.eclipse.hawkbit.repository.model.TenantMetaData;
import org.eclipse.hawkbit.security.DdiSecurityProperties;
import org.eclipse.hawkbit.security.DdiSecurityProperties.Authentication.Anonymous;
import org.eclipse.hawkbit.security.DdiSecurityProperties.Rp;
@@ -33,11 +46,15 @@ import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
+import org.springframework.cache.Cache;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
@@ -54,15 +71,44 @@ import ru.yandex.qatools.allure.annotations.Stories;
*/
@Features("Component Tests - Device Management Federation API")
@Stories("AmqpController Authentication Test")
+@RunWith(MockitoJUnitRunner.class)
public class AmqpControllerAuthenticationTest {
+ private static final String SHA1 = "12345";
+ private static final Long ARTIFACT_ID = 1123L;
+ private static final Long ARTIFACT_SIZE = 6666L;
private static final String TENANT = "DEFAULT";
- private static String CONTROLLLER_ID = "123";
+ private static final Long TENANT_ID = 123L;
+ private static final String CONTROLLER_ID = "123";
+ private static final Long TARGET_ID = 123L;
private AmqpMessageHandlerService amqpMessageHandlerService;
+ private AmqpAuthenticationMessageHandler amqpAuthenticationMessageHandlerService;
+
private MessageConverter messageConverter;
- private TenantConfigurationManagement tenantConfigurationManagement;
+
private AmqpControllerAuthentication authenticationManager;
+ @Mock
+ private TenantConfigurationManagement tenantConfigurationManagementMock;
+
+ @Mock
+ private SystemManagement systemManagement;
+
+ @Mock
+ private Cache cacheMock;
+
+ @Mock
+ private HostnameResolver hostnameResolverMock;
+
+ @Mock
+ private ArtifactManagement artifactManagementMock;
+
+ @Mock
+ private ControllerManagement controllerManagementMock;
+
+ @Mock
+ private Target targteMock;
+
private static final TenantConfigurationValue CONFIG_VALUE_FALSE = TenantConfigurationValue
. builder().value(Boolean.FALSE).build();
@@ -74,8 +120,6 @@ public class AmqpControllerAuthenticationTest {
messageConverter = new Jackson2JsonMessageConverter();
final RabbitTemplate rabbitTemplate = mock(RabbitTemplate.class);
when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter);
- amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate,
- mock(AmqpMessageDispatcherService.class));
final DdiSecurityProperties secruityProperties = mock(DdiSecurityProperties.class);
final Rp rp = mock(Rp.class);
@@ -88,30 +132,57 @@ public class AmqpControllerAuthenticationTest {
when(ddiAuthentication.getAnonymous()).thenReturn(anonymous);
when(anonymous.isEnabled()).thenReturn(false);
- tenantConfigurationManagement = mock(TenantConfigurationManagement.class);
-
- when(tenantConfigurationManagement.getConfigurationValue(any(), eq(Boolean.class)))
+ when(tenantConfigurationManagementMock.getConfigurationValue(any(), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_FALSE);
final ControllerManagement controllerManagement = mock(ControllerManagement.class);
- when(controllerManagement.getSecurityTokenByControllerId(anyString())).thenReturn(CONTROLLLER_ID);
- amqpMessageHandlerService.setArtifactManagement(mock(ArtifactManagement.class));
+ when(controllerManagement.findByControllerId(anyString())).thenReturn(targteMock);
+ when(controllerManagement.findByTargetId(any(Long.class))).thenReturn(targteMock);
+
+ when(targteMock.getSecurityToken()).thenReturn(CONTROLLER_ID);
+ when(targteMock.getControllerId()).thenReturn(CONTROLLER_ID);
final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware();
final SystemSecurityContext systemSecurityContext = new SystemSecurityContext(tenantAware);
- authenticationManager = new AmqpControllerAuthentication(controllerManagement, tenantConfigurationManagement,
- tenantAware, secruityProperties, systemSecurityContext);
+ final TenantMetaData tenantMetaData = mock(TenantMetaData.class);
+ when(tenantMetaData.getTenant()).thenReturn(TENANT);
+ when(systemManagement.getTenantMetadata(TENANT_ID)).thenReturn(tenantMetaData);
+
+ authenticationManager = new AmqpControllerAuthentication(systemManagement, controllerManagement,
+ tenantConfigurationManagementMock, tenantAware, secruityProperties, systemSecurityContext);
authenticationManager.postConstruct();
- amqpMessageHandlerService.setAuthenticationManager(authenticationManager);
+
+ final LocalArtifact testArtifact = new JpaLocalArtifact("afilename", "afilename", new JpaSoftwareModule(
+ new JpaSoftwareModuleType("a key", "a name", null, 1), "a name", null, null, null));
+
+ when(artifactManagementMock.findLocalArtifact(ARTIFACT_ID)).thenReturn(testArtifact);
+ when(artifactManagementMock.findFirstLocalArtifactsBySHA1(SHA1)).thenReturn(testArtifact);
+
+ final DbArtifact artifact = new DbArtifact();
+ artifact.setSize(ARTIFACT_SIZE);
+ artifact.setHashes(new DbArtifactHash("sha1 test", "md5 test"));
+ when(artifactManagementMock.loadLocalArtifactBinary(testArtifact)).thenReturn(artifact);
+
+ amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate,
+ mock(AmqpMessageDispatcherService.class), controllerManagementMock, new JpaEntityFactory());
+
+ amqpAuthenticationMessageHandlerService = new AmqpAuthenticationMessageHandler(rabbitTemplate,
+ authenticationManager, artifactManagementMock, cacheMock, hostnameResolverMock,
+ controllerManagementMock);
+
+ when(hostnameResolverMock.resolveHostname()).thenReturn(new URL("http://localhost"));
+
+ when(controllerManagementMock.hasTargetArtifactAssigned(TARGET_ID, testArtifact)).thenReturn(true);
+ when(controllerManagementMock.hasTargetArtifactAssigned(CONTROLLER_ID, testArtifact)).thenReturn(true);
}
@Test
@Description("Tests authentication manager without principal")
public void testAuthenticationeBadCredantialsWithoutPricipal() {
- final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
- FileResource.createFileResourceBySha1("12345"));
+ final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, TARGET_ID,
+ FileResource.createFileResourceBySha1(SHA1));
try {
authenticationManager.doAuthenticate(securityToken);
fail("BadCredentialsException was excepeted since principal was missing");
@@ -124,12 +195,12 @@ public class AmqpControllerAuthenticationTest {
@Test
@Description("Tests authentication manager without wrong credential")
public void testAuthenticationBadCredantialsWithWrongCredential() {
- final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
- FileResource.createFileResourceBySha1("12345"));
- when(tenantConfigurationManagement.getConfigurationValue(
+ final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, TARGET_ID,
+ FileResource.createFileResourceBySha1(SHA1));
+ when(tenantConfigurationManagementMock.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE);
- securityToken.getHeaders().put(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken 12" + CONTROLLLER_ID);
+ securityToken.putHeader(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken 12" + CONTROLLER_ID);
try {
authenticationManager.doAuthenticate(securityToken);
fail("BadCredentialsException was excepeted due to wrong credential");
@@ -142,12 +213,12 @@ public class AmqpControllerAuthenticationTest {
@Test
@Description("Tests authentication successfull")
public void testSuccessfullAuthentication() {
- final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
- FileResource.createFileResourceBySha1("12345"));
- when(tenantConfigurationManagement.getConfigurationValue(
+ final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, TARGET_ID,
+ FileResource.createFileResourceBySha1(SHA1));
+ when(tenantConfigurationManagementMock.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE);
- securityToken.getHeaders().put(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLLER_ID);
+ securityToken.putHeader(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLER_ID);
final Authentication authentication = authenticationManager.doAuthenticate(securityToken);
assertThat(authentication).isNotNull();
}
@@ -157,13 +228,13 @@ public class AmqpControllerAuthenticationTest {
public void testAuthenticationMessageBadCredantialsWithoutPricipal() {
final MessageProperties messageProperties = createMessageProperties(null);
- final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
- FileResource.createFileResourceBySha1("12345"));
+ final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, TARGET_ID,
+ FileResource.createFileResourceBySha1(SHA1));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties);
// test
- final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message);
+ final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message);
// verify
final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage);
@@ -175,17 +246,17 @@ public class AmqpControllerAuthenticationTest {
@Description("Tests authentication message without wrong credential")
public void testAuthenticationMessageBadCredantialsWithWrongCredential() {
final MessageProperties messageProperties = createMessageProperties(null);
- final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
- FileResource.createFileResourceBySha1("12345"));
- when(tenantConfigurationManagement.getConfigurationValue(
+ final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, TARGET_ID,
+ FileResource.createFileResourceBySha1(SHA1));
+ when(tenantConfigurationManagementMock.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE);
- securityToken.getHeaders().put(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken 12" + CONTROLLLER_ID);
+ securityToken.putHeader(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken 12" + CONTROLLER_ID);
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties);
// test
- final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message);
+ final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message);
// verify
final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage);
@@ -195,24 +266,81 @@ public class AmqpControllerAuthenticationTest {
@Test
@Description("Tests authentication message successfull")
- public void testSuccessfullMessageAuthentication() {
+ public void successfullMessageAuthentication() {
final MessageProperties messageProperties = createMessageProperties(null);
- final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
- FileResource.createFileResourceBySha1("12345"));
- when(tenantConfigurationManagement.getConfigurationValue(
+ final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, null, CONTROLLER_ID, null,
+ FileResource.createFileResourceBySha1(SHA1));
+ when(tenantConfigurationManagementMock.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE);
- securityToken.getHeaders().put(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLLER_ID);
+ securityToken.putHeader(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLER_ID);
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties);
// test
- final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message);
+ final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message);
// verify
final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage);
assertThat(downloadResponse).isNotNull();
- assertThat(downloadResponse.getResponseCode()).isEqualTo(HttpStatus.NOT_FOUND.value());
+ assertThat(downloadResponse.getDownloadUrl()).isNotNull();
+ assertThat(downloadResponse.getResponseCode()).isEqualTo(HttpStatus.OK.value());
+ assertThat(SecurityContextHolder.getContext()).isNotNull();
+ assertThat(SecurityContextHolder.getContext().getAuthentication()).isNotNull();
+ assertThat(SecurityContextHolder.getContext().getAuthentication().getClass().getName())
+ .isEqualTo(PreAuthenticatedAuthenticationToken.class.getName());
+
+ }
+
+ @Test
+ @Description("Tests authentication message successfull with targetId intead of controllerId provided and artifactId instead of SHA1.")
+ public void successfullMessageAuthenticationWithTargetIdAndArtifactId() {
+ final MessageProperties messageProperties = createMessageProperties(null);
+ final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, null, null, TARGET_ID,
+ FileResource.createFileResourceByArtifactId(ARTIFACT_ID));
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
+ .thenReturn(CONFIG_VALUE_TRUE);
+ securityToken.putHeader(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLER_ID);
+ final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
+ messageProperties);
+
+ // test
+ final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message);
+
+ // verify
+ final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage);
+ assertThat(downloadResponse).isNotNull();
+ assertThat(downloadResponse.getDownloadUrl()).isNotNull();
+ assertThat(downloadResponse.getResponseCode()).isEqualTo(HttpStatus.OK.value());
+ assertThat(SecurityContextHolder.getContext()).isNotNull();
+ assertThat(SecurityContextHolder.getContext().getAuthentication()).isNotNull();
+ assertThat(SecurityContextHolder.getContext().getAuthentication().getClass().getName())
+ .isEqualTo(PreAuthenticatedAuthenticationToken.class.getName());
+
+ }
+
+ @Test
+ @Description("Tests authentication message successfull")
+ public void successfullMessageAuthenticationWithTenantid() {
+ final MessageProperties messageProperties = createMessageProperties(null);
+ final TenantSecurityToken securityToken = new TenantSecurityToken(null, TENANT_ID, CONTROLLER_ID, TARGET_ID,
+ FileResource.createFileResourceBySha1(SHA1));
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
+ .thenReturn(CONFIG_VALUE_TRUE);
+ securityToken.putHeader(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLER_ID);
+ final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
+ messageProperties);
+
+ // test
+ final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message);
+
+ // verify
+ final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage);
+ assertThat(downloadResponse).isNotNull();
+ assertThat(downloadResponse.getDownloadUrl()).isNotNull();
+ assertThat(downloadResponse.getResponseCode()).isEqualTo(HttpStatus.OK.value());
assertThat(SecurityContextHolder.getContext()).isNotNull();
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNotNull();
assertThat(SecurityContextHolder.getContext().getAuthentication().getClass().getName())
diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java
index 62bd8e9b7..2fe2709e7 100644
--- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java
+++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java
@@ -13,9 +13,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
@@ -24,6 +22,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import org.eclipse.hawkbit.api.ArtifactUrl;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
@@ -31,11 +30,14 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.DownloadAndUpdateRequest;
import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent;
+import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
+import org.eclipse.hawkbit.repository.model.Target;
+import org.eclipse.hawkbit.repository.model.TenantMetaData;
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
import org.eclipse.hawkbit.util.IpUtil;
import org.junit.Test;
@@ -49,6 +51,8 @@ import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.ActiveProfiles;
+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;
@@ -60,6 +64,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
private static final String TENANT = "default";
+ private static final Long TENANT_ID = 4711L;
private static final URI AMQP_URI = IpUtil.createAmqpUri("vHost", "mytest");
@@ -71,31 +76,47 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
private DefaultAmqpSenderService senderService;
+ private SystemManagement systemManagement;
+
private static final String CONTROLLER_ID = "1";
+ private Target testTarget;
+
@Override
public void before() throws Exception {
super.before();
+ testTarget = entityFactory.generateTarget(CONTROLLER_ID, TEST_TOKEN);
+ testTarget.getTargetInfo().setAddress(AMQP_URI.toString());
+
this.rabbitTemplate = Mockito.mock(RabbitTemplate.class);
when(rabbitTemplate.getMessageConverter()).thenReturn(new Jackson2JsonMessageConverter());
senderService = Mockito.mock(DefaultAmqpSenderService.class);
final ArtifactUrlHandler artifactUrlHandlerMock = Mockito.mock(ArtifactUrlHandler.class);
- when(artifactUrlHandlerMock.getUrl(anyString(), anyLong(), anyString(), anyString(), anyObject()))
- .thenReturn("http://mockurl");
+ when(artifactUrlHandlerMock.getUrls(anyObject(), anyObject()))
+ .thenReturn(Lists.newArrayList(new ArtifactUrl("http", "download", "http://mockurl")));
+
+ systemManagement = Mockito.mock(SystemManagement.class);
+ final TenantMetaData tenantMetaData = Mockito.mock(TenantMetaData.class);
+ when(tenantMetaData.getId()).thenReturn(TENANT_ID);
+ when(tenantMetaData.getTenant()).thenReturn(TENANT);
+
+ when(systemManagement.getTenantMetadata()).thenReturn(tenantMetaData);
amqpMessageDispatcherService = new AmqpMessageDispatcherService(rabbitTemplate, senderService,
- artifactUrlHandlerMock);
+ artifactUrlHandlerMock, systemSecurityContext, systemManagement);
+
}
@Test
@Description("Verfies that download and install event with no software modul works")
public void testSendDownloadRequesWithEmptySoftwareModules() {
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
- 1L, TENANT, CONTROLLER_ID, 1L, new ArrayList(), AMQP_URI, TEST_TOKEN);
+ 1L, TENANT, testTarget, 1L, new ArrayList());
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
- final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress());
+ final Message sendMessage = createArgumentCapture(
+ targetAssignDistributionSetEvent.getTarget().getTargetInfo().getAddress());
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage);
assertThat(downloadAndUpdateRequest.getTargetSecurityToken()).isEqualTo(TEST_TOKEN);
assertTrue("No softwaremmodule should be contained in the request",
@@ -107,9 +128,10 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
public void testSendDownloadRequesWithSoftwareModulesAndNoArtifacts() {
final DistributionSet dsA = testdataFactory.createDistributionSet("");
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
- 1L, TENANT, CONTROLLER_ID, 1L, dsA.getModules(), AMQP_URI, TEST_TOKEN);
+ 1L, TENANT, testTarget, 1L, dsA.getModules());
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
- final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress());
+ final Message sendMessage = createArgumentCapture(
+ targetAssignDistributionSetEvent.getTarget().getTargetInfo().getAddress());
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage);
assertEquals("Expecting a size of 3 software modules in the reuqest", 3,
downloadAndUpdateRequest.getSoftwareModules().size());
@@ -146,9 +168,10 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
Mockito.when(rabbitTemplate.convertSendAndReceive(any())).thenReturn(receivedList);
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
- 1L, TENANT, CONTROLLER_ID, 1L, dsA.getModules(), AMQP_URI, TEST_TOKEN);
+ 1L, TENANT, testTarget, 1L, dsA.getModules());
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
- final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress());
+ final Message sendMessage = createArgumentCapture(
+ targetAssignDistributionSetEvent.getTarget().getTargetInfo().getAddress());
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage);
assertEquals("DownloadAndUpdateRequest event should contains 3 software modules", 3,
downloadAndUpdateRequest.getSoftwareModules().size());
diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java
index a1591c07c..e4c309412 100644
--- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java
+++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java
@@ -54,7 +54,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
-import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -81,8 +80,12 @@ import ru.yandex.qatools.allure.annotations.Stories;
public class AmqpMessageHandlerServiceTest {
private static final String TENANT = "DEFAULT";
+ private static final Long TENANT_ID = 123L;
+ private static String CONTROLLLER_ID = "123";
+ private static final Long TARGET_ID = 123L;
private AmqpMessageHandlerService amqpMessageHandlerService;
+ private AmqpAuthenticationMessageHandler amqpAuthenticationMessageHandlerService;
private MessageConverter messageConverter;
@@ -113,22 +116,16 @@ public class AmqpMessageHandlerServiceTest {
@Mock
private RabbitTemplate rabbitTemplate;
- @Mock
- private SystemSecurityContext systemSecurityContextMock;
-
@Before
public void before() throws Exception {
messageConverter = new Jackson2JsonMessageConverter();
when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter);
- amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate, amqpMessageDispatcherServiceMock);
- amqpMessageHandlerService.setControllerManagement(controllerManagementMock);
- amqpMessageHandlerService.setAuthenticationManager(authenticationManagerMock);
- amqpMessageHandlerService.setArtifactManagement(artifactManagementMock);
- amqpMessageHandlerService.setCache(cacheMock);
- amqpMessageHandlerService.setHostnameResolver(hostnameResolverMock);
- amqpMessageHandlerService.setEntityFactory(entityFactoryMock);
- amqpMessageHandlerService.setSystemSecurityContext(systemSecurityContextMock);
+ amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate, amqpMessageDispatcherServiceMock,
+ controllerManagementMock, entityFactoryMock);
+ amqpAuthenticationMessageHandlerService = new AmqpAuthenticationMessageHandler(rabbitTemplate,
+ authenticationManagerMock, artifactManagementMock, cacheMock, hostnameResolverMock,
+ controllerManagementMock);
}
@Test
@@ -279,13 +276,13 @@ public class AmqpMessageHandlerServiceTest {
@Description("Tests that an download request is denied for an artifact which does not exists")
public void authenticationRequestDeniedForArtifactWhichDoesNotExists() {
final MessageProperties messageProperties = createMessageProperties(null);
- final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123",
+ final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID,
FileResource.createFileResourceBySha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties);
// test
- final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message);
+ final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message);
// verify
final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage);
@@ -298,7 +295,7 @@ public class AmqpMessageHandlerServiceTest {
@Description("Tests that an download request is denied for an artifact which is not assigned to the requested target")
public void authenticationRequestDeniedForArtifactWhichIsNotAssignedToTarget() {
final MessageProperties messageProperties = createMessageProperties(null);
- final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123",
+ final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID,
FileResource.createFileResourceBySha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties);
@@ -309,7 +306,7 @@ public class AmqpMessageHandlerServiceTest {
.thenThrow(EntityNotFoundException.class);
// test
- final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message);
+ final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message);
// verify
final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage);
@@ -322,7 +319,7 @@ public class AmqpMessageHandlerServiceTest {
@Description("Tests that an download request is allowed for an artifact which exists and assigned to the requested target")
public void authenticationRequestAllowedForArtifactWhichExistsAndAssignedToTarget() throws MalformedURLException {
final MessageProperties messageProperties = createMessageProperties(null);
- final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123",
+ final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID,
FileResource.createFileResourceBySha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties);
@@ -340,7 +337,7 @@ public class AmqpMessageHandlerServiceTest {
when(hostnameResolverMock.resolveHostname()).thenReturn(new URL("http://localhost"));
// test
- final Message onMessage = amqpMessageHandlerService.onAuthenticationRequest(message);
+ final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message);
// verify
final DownloadResponse downloadResponse = (DownloadResponse) messageConverter.fromMessage(onMessage);
@@ -364,15 +361,12 @@ public class AmqpMessageHandlerServiceTest {
when(controllerManagementMock.addUpdateActionStatus(Matchers.any())).thenReturn(action);
when(entityFactoryMock.generateActionStatus()).thenReturn(new JpaActionStatus());
// for the test the same action can be used
- when(controllerManagementMock.findOldestActiveActionByTarget(Matchers.any()))
- .thenReturn(Optional.of(action));
+ when(controllerManagementMock.findOldestActiveActionByTarget(Matchers.any())).thenReturn(Optional.of(action));
final List softwareModuleList = createSoftwareModuleList();
when(controllerManagementMock.findSoftwareModulesByDistributionSet(Matchers.any()))
.thenReturn(softwareModuleList);
- when(systemSecurityContextMock.runAsSystem(anyObject())).thenReturn("securityToken");
-
final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT);
messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name());
final ActionUpdateStatus actionUpdateStatus = createActionUpdateStatus(ActionStatus.FINISHED, 23L);
@@ -393,10 +387,10 @@ public class AmqpMessageHandlerServiceTest {
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = captorTargetAssignDistributionSetEvent
.getValue();
- assertThat(targetAssignDistributionSetEvent.getControllerId()).as("event has wrong controller id")
+ assertThat(targetAssignDistributionSetEvent.getTarget().getControllerId()).as("event has wrong controller id")
.isEqualTo("target1");
- assertThat(targetAssignDistributionSetEvent.getTargetToken()).as("targetoken not filled correctly")
- .isEqualTo(action.getTarget().getSecurityToken());
+ assertThat(targetAssignDistributionSetEvent.getTarget().getSecurityToken())
+ .as("targetoken not filled correctly").isEqualTo(action.getTarget().getSecurityToken());
assertThat(targetAssignDistributionSetEvent.getActionId()).as("event has wrong action id").isEqualTo(22L);
assertThat(targetAssignDistributionSetEvent.getSoftwareModules()).as("event has wrong sofware modules")
.isEqualTo(softwareModuleList);
diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java
index 20d03bdd6..582bcf130 100644
--- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java
+++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java
@@ -52,8 +52,8 @@ public class BaseAmqpServiceTest {
final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus();
actionUpdateStatus.setActionId(1L);
actionUpdateStatus.setSoftwareModuleId(2L);
- actionUpdateStatus.getMessage().add("Message 1");
- actionUpdateStatus.getMessage().add("Message 2");
+ actionUpdateStatus.addMessage("Message 1");
+ actionUpdateStatus.addMessage("Message 2");
final Message message = rabbitTemplate.getMessageConverter().toMessage(actionUpdateStatus,
new MessageProperties());
diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java
deleted file mode 100644
index ea01bc0ec..000000000
--- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java
+++ /dev/null
@@ -1,95 +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.util;
-
-import static org.junit.Assert.assertEquals;
-
-import org.eclipse.hawkbit.AmqpTestConfiguration;
-import org.eclipse.hawkbit.api.ArtifactUrlHandler;
-import org.eclipse.hawkbit.api.UrlProtocol;
-import org.eclipse.hawkbit.repository.model.DistributionSet;
-import org.eclipse.hawkbit.repository.model.LocalArtifact;
-import org.eclipse.hawkbit.repository.model.SoftwareModule;
-import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
-import org.junit.Before;
-import org.junit.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.SpringApplicationConfiguration;
-
-import ru.yandex.qatools.allure.annotations.Description;
-import ru.yandex.qatools.allure.annotations.Features;
-import ru.yandex.qatools.allure.annotations.Stories;
-
-/**
- * Tests for creating urls to download artifacts.
- */
-@Features("Component Tests - Artifact URL Handler")
-@Stories("Test to generate the artifact download URL")
-@SpringApplicationConfiguration(classes = { AmqpTestConfiguration.class,
- org.eclipse.hawkbit.RepositoryApplicationConfiguration.class })
-public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest {
-
- private static final String HTTPS_LOCALHOST = "https://localhost/";
- private static final String HTTP_LOCALHOST = "http://localhost/";
-
- @Autowired
- private ArtifactUrlHandler urlHandlerProperties;
-
- private LocalArtifact localArtifact;
- private static final String CONTROLLER_ID = "Test";
- private String fileName;
- private Long softwareModuleId;
- private String sha1Hash;
-
- @Before
- public void setup() {
- final DistributionSet dsA = testdataFactory.createDistributionSet("");
- final SoftwareModule module = dsA.getModules().iterator().next();
- localArtifact = testdataFactory.createLocalArtifacts(module.getId()).stream().findAny().get();
- softwareModuleId = localArtifact.getSoftwareModule().getId();
- fileName = localArtifact.getFilename();
- sha1Hash = localArtifact.getSha1Hash();
-
- }
-
- @Test
- @Description("Tests the generation of http download url.")
- public void testHttpUrl() {
-
- final String url = urlHandlerProperties.getUrl(CONTROLLER_ID, softwareModuleId, fileName, sha1Hash,
- UrlProtocol.HTTP);
- assertEquals("http is build incorrect",
- HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + CONTROLLER_ID
- + "/softwaremodules/" + localArtifact.getSoftwareModule().getId() + "/artifacts/"
- + localArtifact.getFilename(),
- url);
- }
-
- @Test
- @Description("Tests the generation of https download url.")
- public void testHttpsUrl() {
- final String url = urlHandlerProperties.getUrl(CONTROLLER_ID, softwareModuleId, fileName, sha1Hash,
- UrlProtocol.HTTPS);
- assertEquals("https is build incorrect",
- HTTPS_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + CONTROLLER_ID
- + "/softwaremodules/" + localArtifact.getSoftwareModule().getId() + "/artifacts/"
- + localArtifact.getFilename(),
- url);
- }
-
- @Test
- @Description("Tests the generation of coap download url.")
- public void testCoapUrl() {
- final String url = urlHandlerProperties.getUrl(CONTROLLER_ID, softwareModuleId, fileName, sha1Hash,
- UrlProtocol.COAP);
-
- assertEquals("coap is build incorrect", "coap://127.0.0.1:5683/fw/" + tenantAware.getCurrentTenant() + "/"
- + CONTROLLER_ID + "/sha1/" + localArtifact.getSha1Hash(), url);
- }
-}
diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ActionUpdateStatus.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ActionUpdateStatus.java
index ac0926080..2262cab96 100644
--- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ActionUpdateStatus.java
+++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ActionUpdateStatus.java
@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.dmf.json.model;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -18,9 +19,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/**
* JSON representation of action update status.
- *
- *
- *
*/
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@@ -32,7 +30,7 @@ public class ActionUpdateStatus {
@JsonProperty(required = true)
private ActionStatus actionStatus;
@JsonProperty
- private final List message = new ArrayList<>();
+ private List message;
public Long getActionId() {
return actionId;
@@ -59,7 +57,19 @@ public class ActionUpdateStatus {
}
public List getMessage() {
- return message;
+ if (message == null) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(message);
+ }
+
+ public boolean addMessage(final String message) {
+ if (this.message == null) {
+ this.message = new ArrayList<>();
+ }
+
+ return this.message.add(message);
}
}
diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/Artifact.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/Artifact.java
index 27da75fb0..8375663b8 100644
--- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/Artifact.java
+++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/Artifact.java
@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.dmf.json.model;
-import java.util.EnumMap;
+import java.util.Collections;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -25,15 +25,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class Artifact {
-
- /**
- * Represented the supported protocols for artifact url's.
- *
- */
- public enum UrlProtocol {
- COAP, HTTP, HTTPS
- }
-
@JsonProperty
private String filename;
@@ -44,13 +35,17 @@ public class Artifact {
private Long size;
@JsonProperty
- private Map urls = new EnumMap<>(UrlProtocol.class);
+ private Map urls;
- public Map getUrls() {
- return urls;
+ public Map getUrls() {
+ if (urls == null) {
+ return Collections.emptyMap();
+ }
+
+ return Collections.unmodifiableMap(urls);
}
- public void setUrls(final Map urls) {
+ public void setUrls(final Map urls) {
this.urls = urls;
}
diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java
index 88cb80975..8664f639e 100644
--- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java
+++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java
@@ -8,7 +8,8 @@
*/
package org.eclipse.hawkbit.dmf.json.model;
-import java.util.LinkedList;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -30,7 +31,7 @@ public class DownloadAndUpdateRequest {
private String targetSecurityToken;
@JsonProperty
- private final List softwareModules = new LinkedList<>();
+ private List softwareModules;
public Long getActionId() {
return actionId;
@@ -49,7 +50,11 @@ public class DownloadAndUpdateRequest {
}
public List getSoftwareModules() {
- return softwareModules;
+ if (softwareModules == null) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(softwareModules);
}
/**
@@ -59,6 +64,10 @@ public class DownloadAndUpdateRequest {
* the module
*/
public void addSoftwareModule(final SoftwareModule createSoftwareModule) {
+ if (softwareModules == null) {
+ softwareModules = new ArrayList<>();
+ }
+
softwareModules.add(createSoftwareModule);
}
diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/SoftwareModule.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/SoftwareModule.java
index 193f33575..70a7880d8 100644
--- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/SoftwareModule.java
+++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/SoftwareModule.java
@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.dmf.json.model;
-import java.util.LinkedList;
+import java.util.Collections;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -35,7 +35,7 @@ public class SoftwareModule {
@JsonProperty
private String moduleVersion;
@JsonProperty
- private List artifacts = new LinkedList<>();
+ private List artifacts;
public String getModuleType() {
return moduleType;
@@ -54,7 +54,11 @@ public class SoftwareModule {
}
public List getArtifacts() {
- return artifacts;
+ if (artifacts == null) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(artifacts);
}
public Long getModuleId() {
diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java
index 19293f3eb..d2248fed8 100644
--- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java
+++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java
@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.dmf.json.model;
+import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
@@ -27,16 +28,47 @@ public class TenantSecurityToken {
public static final String AUTHORIZATION_HEADER = "Authorization";
- @JsonProperty
- private final String tenant;
- @JsonProperty
+ @JsonProperty(required = false)
+ private String tenant;
+ @JsonProperty(required = false)
+ private final Long tenantId;
+ @JsonProperty(required = false)
private final String controllerId;
@JsonProperty(required = false)
- private Map headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ private final Long targetId;
+
+ @JsonProperty(required = false)
+ private Map headers;
@JsonProperty(required = false)
private final FileResource fileResource;
+ /**
+ * Constructor.
+ *
+ * @param tenant
+ * the tenant for the security token
+ * @param tenantId
+ * alternative tenant identification by technical ID
+ * @param controllerId
+ * the ID of the controller for the security token
+ * @param targetId
+ * alternative target identification by technical ID
+ * @param fileResource
+ * the file to obtain
+ */
+ @JsonCreator
+ public TenantSecurityToken(@JsonProperty("tenant") final String tenant,
+ @JsonProperty("tenantId") final Long tenantId, @JsonProperty("controllerId") final String controllerId,
+ @JsonProperty("targetId") final Long targetId,
+ @JsonProperty("fileResource") final FileResource fileResource) {
+ this.tenant = tenant;
+ this.tenantId = tenantId;
+ this.controllerId = controllerId;
+ this.targetId = targetId;
+ this.fileResource = fileResource;
+ }
+
/**
* Constructor.
*
@@ -47,13 +79,26 @@ public class TenantSecurityToken {
* @param fileResource
* the file to obtain
*/
- @JsonCreator
- public TenantSecurityToken(@JsonProperty("tenant") final String tenant,
- @JsonProperty("controllerId") final String controllerId,
- @JsonProperty("fileResource") final FileResource fileResource) {
+ public TenantSecurityToken(final String tenant, final String controllerId, final FileResource fileResource) {
+ this(tenant, null, controllerId, null, fileResource);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param tenantId
+ * the tenant for the security token
+ * @param targetId
+ * target identification by technical ID
+ * @param fileResource
+ * the file to obtain
+ */
+ public TenantSecurityToken(final Long tenantId, final Long targetId, final FileResource fileResource) {
+ this(null, tenantId, null, targetId, fileResource);
+ }
+
+ public void setTenant(final String tenant) {
this.tenant = tenant;
- this.controllerId = controllerId;
- this.fileResource = fileResource;
}
public String getTenant() {
@@ -65,13 +110,25 @@ public class TenantSecurityToken {
}
public Map getHeaders() {
- return headers;
+ if (headers == null) {
+ return Collections.emptyMap();
+ }
+
+ return Collections.unmodifiableMap(headers);
}
public FileResource getFileResource() {
return fileResource;
}
+ public Long getTenantId() {
+ return tenantId;
+ }
+
+ public Long getTargetId() {
+ return targetId;
+ }
+
/**
* Gets a header value.
*
@@ -80,6 +137,10 @@ public class TenantSecurityToken {
* @return the value
*/
public String getHeader(final String name) {
+ if (headers == null) {
+ return null;
+ }
+
return headers.get(name);
}
@@ -88,6 +149,24 @@ public class TenantSecurityToken {
this.headers.putAll(headers);
}
+ /**
+ * Associates the specified header value with the specified name.
+ *
+ * @param name
+ * of the header
+ * @param value
+ * of the header
+ *
+ * @return the previous value associated with the name, or
+ * null if there was no mapping for name.
+ */
+ public String putHeader(final String name, final String value) {
+ if (headers == null) {
+ headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ }
+ return headers.put(name, value);
+ }
+
/**
* File resource descriptor which is used to ask for the resource to
* download e.g. The lookup of the file can be different e.g. by SHA1 hash
@@ -99,6 +178,8 @@ public class TenantSecurityToken {
@JsonProperty(required = false)
private String sha1;
@JsonProperty(required = false)
+ private Long artifactId;
+ @JsonProperty(required = false)
private String filename;
@JsonProperty(required = false)
private SoftwareModuleFilenameResource softwareModuleFilenameResource;
@@ -128,6 +209,14 @@ public class TenantSecurityToken {
this.softwareModuleFilenameResource = softwareModuleFilenameResource;
}
+ public Long getArtifactId() {
+ return artifactId;
+ }
+
+ public void setArtifactId(final Long artifactId) {
+ this.artifactId = artifactId;
+ }
+
/**
* factory method to create a file resource for an SHA1 lookup.
*
@@ -141,6 +230,19 @@ public class TenantSecurityToken {
return resource;
}
+ /**
+ * factory method to create a file resource for an artifact ID lookup.
+ *
+ * @param artifactId
+ * the artifact IF key of the file to obtain
+ * @return the {@link FileResource} with SHA1 key set
+ */
+ public static FileResource createFileResourceByArtifactId(final Long artifactId) {
+ final FileResource resource = new FileResource();
+ resource.artifactId = artifactId;
+ return resource;
+ }
+
/**
* factory method to create a file resource for an filename lookup.
*
@@ -173,7 +275,7 @@ public class TenantSecurityToken {
@Override
public String toString() {
- return "FileResource [sha1=" + sha1 + ", filename=" + filename + "]";
+ return "FileResource [sha1=" + sha1 + ", artifactId=" + artifactId + ", filename=" + filename + "]";
}
/**
diff --git a/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/AbstractHttpControllerAuthenticationFilter.java b/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/AbstractHttpControllerAuthenticationFilter.java
index 2f2726d98..f62307789 100644
--- a/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/AbstractHttpControllerAuthenticationFilter.java
+++ b/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/AbstractHttpControllerAuthenticationFilter.java
@@ -168,10 +168,10 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
private TenantSecurityToken createTenantSecruityTokenVariables(final HttpServletRequest request,
final String tenant, final String controllerId) {
- final TenantSecurityToken secruityToken = new TenantSecurityToken(tenant, controllerId,
+ final TenantSecurityToken secruityToken = new TenantSecurityToken(tenant, null, controllerId, null,
FileResource.createFileResourceBySha1(""));
final UnmodifiableIterator forEnumeration = Iterators.forEnumeration(request.getHeaderNames());
- forEnumeration.forEachRemaining(header -> secruityToken.getHeaders().put(header, request.getHeader(header)));
+ forEnumeration.forEachRemaining(header -> secruityToken.putHeader(header, request.getHeader(header)));
return secruityToken;
}
diff --git a/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/PagedList.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/PagedList.java
index 173f3ce31..534cfa98d 100644
--- a/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/PagedList.java
+++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/PagedList.java
@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.mgmt.json.model;
+import java.util.Collections;
import java.util.List;
import javax.validation.constraints.NotNull;
@@ -72,7 +73,7 @@ public class PagedList extends ResourceSupport {
}
public List getContent() {
- return content;
+ return Collections.unmodifiableList(content);
}
}
diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetMapper.java
index 4a0f8d90e..acd088c85 100644
--- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetMapper.java
+++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetMapper.java
@@ -12,7 +12,10 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.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.distributionset.MgmtDistributionSet;
@@ -34,10 +37,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
/**
* A mapper which maps repository model to RESTful model representation and
* back.
- *
- *
- *
- *
*/
public final class MgmtDistributionSetMapper {
private MgmtDistributionSetMapper() {
@@ -75,15 +74,13 @@ public final class MgmtDistributionSetMapper {
* to use for conversion
* @return converted list of {@link DistributionSet}s
*/
- static List dsFromRequest(final Iterable sets,
+ static List dsFromRequest(final Collection sets,
final SoftwareManagement softwareManagement, final DistributionSetManagement distributionSetManagement,
final EntityFactory entityFactory) {
- final List mappedList = new ArrayList<>();
- for (final MgmtDistributionSetRequestBodyPost dsRest : sets) {
- mappedList.add(fromRequest(dsRest, softwareManagement, distributionSetManagement, entityFactory));
- }
- return mappedList;
+ return sets.stream()
+ .map(dsRest -> fromRequest(dsRest, softwareManagement, distributionSetManagement, entityFactory))
+ .collect(Collectors.toList());
}
@@ -139,15 +136,12 @@ public final class MgmtDistributionSetMapper {
*/
static List fromRequestDsMetadata(final DistributionSet ds,
final List metadata, final EntityFactory entityFactory) {
- final List mappedList = new ArrayList<>(metadata.size());
- for (final MgmtMetadata metadataRest : metadata) {
- if (metadataRest.getKey() == null) {
- throw new IllegalArgumentException("the key of the metadata must be present");
- }
- mappedList.add(
- entityFactory.generateDistributionSetMetadata(ds, metadataRest.getKey(), metadataRest.getValue()));
+ if (metadata == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return metadata.stream().map(metadataRest -> entityFactory.generateDistributionSetMetadata(ds,
+ metadataRest.getKey(), metadataRest.getValue())).collect(Collectors.toList());
}
/**
@@ -196,15 +190,12 @@ public final class MgmtDistributionSetMapper {
return result;
}
- static List toResponseDistributionSets(final Iterable sets) {
- final List response = new ArrayList<>();
- if (sets != null) {
-
- for (final DistributionSet set : sets) {
- response.add(toResponse(set));
- }
+ static List toResponseDistributionSets(final Collection sets) {
+ if (sets == null) {
+ return Collections.emptyList();
}
- return response;
+
+ return sets.stream().map(MgmtDistributionSetMapper::toResponse).collect(Collectors.toList());
}
static MgmtMetadata toResponseDsMetadata(final DistributionSetMetadata metadata) {
@@ -224,14 +215,10 @@ public final class MgmtDistributionSetMapper {
}
static List toResponseFromDsList(final List sets) {
- final List mappedList = new ArrayList<>();
- if (sets != null) {
- for (final DistributionSet set : sets) {
- final MgmtDistributionSet response = toResponse(set);
-
- mappedList.add(response);
- }
+ if (sets == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return sets.stream().map(MgmtDistributionSetMapper::toResponse).collect(Collectors.toList());
}
}
diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java
index 721995d88..b49654460 100644
--- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java
+++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java
@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -123,7 +124,7 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
.runAsSystem(() -> this.systemManagement.getTenantMetadata().getDefaultDsType().getKey());
sets.stream().filter(ds -> ds.getType() == null).forEach(ds -> ds.setType(defaultDsKey));
- final Iterable createdDSets = this.distributionSetManagement
+ final Collection createdDSets = this.distributionSetManagement
.createDistributionSets(MgmtDistributionSetMapper.dsFromRequest(sets, this.softwareManagement,
this.distributionSetManagement, entityFactory));
diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeMapper.java
index 675fe9df0..33b81ab73 100644
--- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeMapper.java
+++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeMapper.java
@@ -11,8 +11,10 @@ package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
-import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType;
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost;
@@ -39,13 +41,13 @@ final class MgmtDistributionSetTypeMapper {
static List smFromRequest(final EntityFactory entityFactory,
final SoftwareManagement softwareManagement,
- final Iterable smTypesRest) {
- final List mappedList = new ArrayList<>();
-
- for (final MgmtDistributionSetTypeRequestBodyPost smRest : smTypesRest) {
- mappedList.add(fromRequest(entityFactory, softwareManagement, smRest));
+ final Collection smTypesRest) {
+ if (smTypesRest == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return smTypesRest.stream().map(smRest -> fromRequest(entityFactory, softwareManagement, smRest))
+ .collect(Collectors.toList());
}
static DistributionSetType fromRequest(final EntityFactory entityFactory,
@@ -91,19 +93,19 @@ final class MgmtDistributionSetTypeMapper {
}
static List toTypesResponse(final List types) {
- final List response = new ArrayList<>();
- for (final DistributionSetType dsType : types) {
- response.add(toResponse(dsType));
+ if (types == null) {
+ return Collections.emptyList();
}
- return response;
+
+ return types.stream().map(MgmtDistributionSetTypeMapper::toResponse).collect(Collectors.toList());
}
static List toListResponse(final List types) {
- final List response = new ArrayList<>();
- for (final DistributionSetType dsType : types) {
- response.add(toResponse(dsType));
+ if (types == null) {
+ return Collections.emptyList();
}
- return response;
+
+ return types.stream().map(MgmtDistributionSetTypeMapper::toResponse).collect(Collectors.toList());
}
static MgmtDistributionSetType toResponse(final DistributionSetType type) {
diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResource.java
index d69e4d8d4..fe62ff369 100644
--- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResource.java
+++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResource.java
@@ -8,6 +8,12 @@
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
+import static org.eclipse.hawkbit.mgmt.rest.resource.MgmtDistributionSetTypeMapper.toResponse;
+import static org.eclipse.hawkbit.mgmt.rest.resource.MgmtDistributionSetTypeMapper.toTypesResponse;
+import static org.eclipse.hawkbit.mgmt.rest.resource.MgmtSoftwareModuleTypeMapper.toResponse;
+import static org.eclipse.hawkbit.mgmt.rest.resource.MgmtSoftwareModuleTypeMapper.toTypesResponse;
+import static org.springframework.http.HttpStatus.CREATED;
+
import java.util.List;
import org.eclipse.hawkbit.mgmt.json.model.MgmtId;
@@ -32,7 +38,6 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
-import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
@@ -42,8 +47,6 @@ import org.springframework.web.bind.annotation.RestController;
/**
* REST Resource handling for {@link SoftwareModule} and related
* {@link Artifact} CRUD operations.
- *
- *
*/
@RestController
public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeRestApi {
@@ -67,7 +70,6 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
final Sort sorting = PagingUtility.sanitizeDistributionSetTypeSortParam(sortParam);
-
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
final Slice findModuleTypessAll;
@@ -82,31 +84,32 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
final List rest = MgmtDistributionSetTypeMapper
.toListResponse(findModuleTypessAll.getContent());
- return new ResponseEntity<>(new PagedList<>(rest, countModulesAll), HttpStatus.OK);
+ return ResponseEntity.ok(new PagedList<>(rest, countModulesAll));
}
@Override
public ResponseEntity getDistributionSetType(
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
- final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
- return new ResponseEntity<>(MgmtDistributionSetTypeMapper.toResponse(foundType), HttpStatus.OK);
+ final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
+ return ResponseEntity.ok(toResponse(foundType));
}
@Override
public ResponseEntity deleteDistributionSetType(
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
- final DistributionSetType module = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
+ final DistributionSetType module = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
distributionSetManagement.deleteDistributionSetType(module);
- return new ResponseEntity<>(HttpStatus.OK);
+ return ResponseEntity.ok().build();
}
@Override
public ResponseEntity updateDistributionSetType(
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
@RequestBody final MgmtDistributionSetTypeRequestBodyPut restDistributionSetType) {
+
final DistributionSetType type = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
// only description can be modified
@@ -117,8 +120,7 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
final DistributionSetType updatedDistributionSetType = distributionSetManagement
.updateDistributionSetType(type);
- return new ResponseEntity<>(MgmtDistributionSetTypeMapper.toResponse(updatedDistributionSetType),
- HttpStatus.OK);
+ return ResponseEntity.ok(toResponse(updatedDistributionSetType));
}
@Override
@@ -128,16 +130,17 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
final List createdSoftwareModules = distributionSetManagement.createDistributionSetTypes(
MgmtDistributionSetTypeMapper.smFromRequest(entityFactory, softwareManagement, distributionSetTypes));
- return new ResponseEntity<>(MgmtDistributionSetTypeMapper.toTypesResponse(createdSoftwareModules),
- HttpStatus.CREATED);
+ return ResponseEntity.status(CREATED).body(toTypesResponse(createdSoftwareModules));
}
private DistributionSetType findDistributionSetTypeWithExceptionIfNotFound(final Long distributionSetTypeId) {
+
final DistributionSetType module = distributionSetManagement.findDistributionSetTypeById(distributionSetTypeId);
if (module == null) {
throw new EntityNotFoundException(
"DistributionSetType with Id {" + distributionSetTypeId + "} does not exist");
}
+
return module;
}
@@ -146,8 +149,7 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
- return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toListResponse(foundType.getMandatoryModuleTypes()),
- HttpStatus.OK);
+ return ResponseEntity.ok(toTypesResponse(foundType.getMandatoryModuleTypes()));
}
@Override
@@ -156,7 +158,6 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
-
final SoftwareModuleType foundSmType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId);
if (!foundType.containsMandatoryModuleType(foundSmType)) {
@@ -164,7 +165,7 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
"Software module with given ID is not part of this distribution set type!");
}
- return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toResponse(foundSmType), HttpStatus.OK);
+ return ResponseEntity.ok(toResponse(foundSmType));
}
@Override
@@ -173,7 +174,6 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
-
final SoftwareModuleType foundSmType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId);
if (!foundType.containsOptionalModuleType(foundSmType)) {
@@ -181,7 +181,7 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
"Software module with given ID is not part of this distribution set type!");
}
- return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toResponse(foundSmType), HttpStatus.OK);
+ return ResponseEntity.ok(toResponse(foundSmType));
}
@Override
@@ -189,9 +189,7 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
-
- return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toListResponse(foundType.getOptionalModuleTypes()),
- HttpStatus.OK);
+ return ResponseEntity.ok(toTypesResponse(foundType.getOptionalModuleTypes()));
}
@Override
@@ -200,7 +198,6 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
-
final SoftwareModuleType foundSmType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId);
if (!foundType.containsMandatoryModuleType(foundSmType)) {
@@ -209,18 +206,17 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
}
foundType.removeModuleType(softwareModuleTypeId);
-
distributionSetManagement.updateDistributionSetType(foundType);
- return new ResponseEntity<>(HttpStatus.OK);
+ return ResponseEntity.ok().build();
}
@Override
public ResponseEntity removeOptionalModule(
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
- final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
+ final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
final SoftwareModuleType foundSmType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId);
if (!foundType.containsOptionalModuleType(foundSmType)) {
@@ -229,10 +225,9 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
}
foundType.removeModuleType(softwareModuleTypeId);
-
distributionSetManagement.updateDistributionSetType(foundType);
- return new ResponseEntity<>(HttpStatus.OK);
+ return ResponseEntity.ok().build();
}
@Override
@@ -240,14 +235,11 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @RequestBody final MgmtId smtId) {
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
-
final SoftwareModuleType smType = findSoftwareModuleTypeWithExceptionIfNotFound(smtId.getId());
-
foundType.addMandatoryModuleType(smType);
-
distributionSetManagement.updateDistributionSetType(foundType);
- return new ResponseEntity<>(HttpStatus.OK);
+ return ResponseEntity.ok().build();
}
@Override
@@ -255,23 +247,22 @@ public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeR
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @RequestBody final MgmtId smtId) {
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
-
final SoftwareModuleType smType = findSoftwareModuleTypeWithExceptionIfNotFound(smtId.getId());
-
foundType.addOptionalModuleType(smType);
distributionSetManagement.updateDistributionSetType(foundType);
- return new ResponseEntity<>(HttpStatus.OK);
-
+ return ResponseEntity.ok().build();
}
private SoftwareModuleType findSoftwareModuleTypeWithExceptionIfNotFound(final Long softwareModuleTypeId) {
+
final SoftwareModuleType module = softwareManagement.findSoftwareModuleTypeById(softwareModuleTypeId);
if (module == null) {
throw new EntityNotFoundException(
"SoftwareModuleType with Id {" + softwareModuleTypeId + "} does not exist");
}
+
return module;
}
}
diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutMapper.java
index 7467a45b0..2a092851d 100644
--- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutMapper.java
+++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutMapper.java
@@ -11,8 +11,9 @@ package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition.Condition;
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutErrorAction.ErrorAction;
@@ -48,9 +49,11 @@ final class MgmtRolloutMapper {
}
static List toResponseRollout(final List rollouts) {
- final List result = new ArrayList<>(rollouts.size());
- rollouts.forEach(r -> result.add(toResponseRollout(r)));
- return result;
+ if (rollouts == null) {
+ return Collections.emptyList();
+ }
+
+ return rollouts.stream().map(MgmtRolloutMapper::toResponseRollout).collect(Collectors.toList());
}
static MgmtRolloutResponseBody toResponseRollout(final Rollout rollout) {
@@ -103,9 +106,11 @@ final class MgmtRolloutMapper {
}
static List toResponseRolloutGroup(final List rollouts) {
- final List result = new ArrayList<>(rollouts.size());
- rollouts.forEach(r -> result.add(toResponseRolloutGroup(r)));
- return result;
+ if (rollouts == null) {
+ return Collections.emptyList();
+ }
+
+ return rollouts.stream().map(MgmtRolloutMapper::toResponseRolloutGroup).collect(Collectors.toList());
}
static MgmtRolloutGroupResponseBody toResponseRolloutGroup(final RolloutGroup rolloutGroup) {
diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java
index 3960fb3c2..2166a7e43 100644
--- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java
+++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java
@@ -11,8 +11,10 @@ package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
-import java.util.ArrayList;
+import java.util.Collection;
+import java.util.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;
@@ -65,60 +67,46 @@ public final class MgmtSoftwareModuleMapper {
}
static List fromRequestSwMetadata(final EntityFactory entityFactory,
- final SoftwareModule sw, final List metadata) {
- final List mappedList = new ArrayList<>(metadata.size());
- for (final MgmtMetadata metadataRest : metadata) {
- if (metadataRest.getKey() == null) {
- throw new IllegalArgumentException("the key of the metadata must be present");
- }
- mappedList.add(
- entityFactory.generateSoftwareModuleMetadata(sw, metadataRest.getKey(), metadataRest.getValue()));
+ final SoftwareModule sw, final Collection metadata) {
+ if (metadata == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return metadata.stream().map(metadataRest -> entityFactory.generateSoftwareModuleMetadata(sw,
+ metadataRest.getKey(), metadataRest.getValue())).collect(Collectors.toList());
}
static List smFromRequest(final EntityFactory entityFactory,
- final Iterable smsRest, final SoftwareManagement softwareManagement) {
- final List mappedList = new ArrayList<>();
- for (final MgmtSoftwareModuleRequestBodyPost smRest : smsRest) {
- mappedList.add(fromRequest(entityFactory, smRest, softwareManagement));
+ final Collection smsRest, final SoftwareManagement softwareManagement) {
+ if (smsRest == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return smsRest.stream().map(smRest -> fromRequest(entityFactory, smRest, softwareManagement))
+ .collect(Collectors.toList());
}
/**
* Create response for sw modules.
*
- * @param baseSoftareModules
+ * @param softwareModules
* the modules
* @return the response
*/
- public static List toResponse(final List baseSoftareModules) {
- final List mappedList = new ArrayList<>();
- if (baseSoftareModules != null) {
- for (final SoftwareModule target : baseSoftareModules) {
- final MgmtSoftwareModule response = toResponse(target);
-
- mappedList.add(response);
- }
+ public static List toResponse(final Collection softwareModules) {
+ if (softwareModules == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return softwareModules.stream().map(MgmtSoftwareModuleMapper::toResponse).collect(Collectors.toList());
}
- static List toResponseSoftwareModules(final Iterable softwareModules) {
- final List response = new ArrayList<>();
- for (final SoftwareModule softwareModule : softwareModules) {
- response.add(toResponse(softwareModule));
+ static List toResponseSwMetadata(final Collection metadata) {
+ if (metadata == null) {
+ return Collections.emptyList();
}
- return response;
- }
- static List toResponseSwMetadata(final List metadata) {
- final List mappedList = new ArrayList<>(metadata.size());
- for (final SoftwareModuleMetadata distributionSetMetadata : metadata) {
- mappedList.add(toResponseSwMetadata(distributionSetMetadata));
- }
- return mappedList;
+ return metadata.stream().map(MgmtSoftwareModuleMapper::toResponseSwMetadata).collect(Collectors.toList());
}
static MgmtMetadata toResponseSwMetadata(final SoftwareModuleMetadata metadata) {
@@ -194,15 +182,11 @@ public final class MgmtSoftwareModuleMapper {
return artifactRest;
}
- static List artifactsToResponse(final List artifacts) {
- final List mappedList = new ArrayList<>();
-
- if (artifacts != null) {
- for (final Artifact artifact : artifacts) {
- final MgmtArtifact response = toResponse(artifact);
- mappedList.add(response);
- }
+ static List artifactsToResponse(final Collection artifacts) {
+ if (artifacts == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return artifacts.stream().map(MgmtSoftwareModuleMapper::toResponse).collect(Collectors.toList());
}
}
diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java
index b475c473f..1706a8030 100644
--- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java
+++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java
@@ -8,7 +8,15 @@
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
+import static org.eclipse.hawkbit.mgmt.rest.resource.MgmtSoftwareModuleMapper.artifactsToResponse;
+import static org.eclipse.hawkbit.mgmt.rest.resource.MgmtSoftwareModuleMapper.toResponse;
+import static org.eclipse.hawkbit.mgmt.rest.resource.MgmtSoftwareModuleMapper.toResponseSwMetadata;
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+import static org.springframework.http.HttpStatus.CREATED;
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
+
import java.io.IOException;
+import java.util.Collection;
import java.util.List;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
@@ -46,10 +54,10 @@ import org.springframework.web.multipart.MultipartFile;
/**
* REST Resource handling for {@link SoftwareModule} and related
* {@link Artifact} CRUD operations.
- *
*/
@RestController
public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
+
private static final Logger LOG = LoggerFactory.getLogger(MgmtSoftwareModuleResource.class);
@Autowired
@@ -69,7 +77,7 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
@RequestParam(value = "sha1sum", required = false) final String sha1Sum) {
if (file.isEmpty()) {
- return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
+ return new ResponseEntity<>(BAD_REQUEST);
}
String fileName = optionalFileName;
@@ -81,10 +89,10 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
final Artifact result = artifactManagement.createLocalArtifact(file.getInputStream(), softwareModuleId,
fileName, md5Sum == null ? null : md5Sum.toLowerCase(),
sha1Sum == null ? null : sha1Sum.toLowerCase(), false, file.getContentType());
- return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponse(result), HttpStatus.CREATED);
+ return ResponseEntity.status(CREATED).body(toResponse(result));
} catch (final IOException e) {
LOG.error("Failed to store artifact", e);
- return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+ return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
}
}
@@ -92,31 +100,34 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
@ResponseBody
public ResponseEntity> getArtifacts(
@PathVariable("softwareModuleId") final Long softwareModuleId) {
- final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
- return new ResponseEntity<>(MgmtSoftwareModuleMapper.artifactsToResponse(module.getArtifacts()), HttpStatus.OK);
+ final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
+ return ResponseEntity.ok(artifactsToResponse(module.getArtifacts()));
}
@Override
@ResponseBody
+ // Exception squid:S3655 - Optional access is checked in
+ // findSoftwareModuleWithExceptionIfNotFound
+ // subroutine
+ @SuppressWarnings("squid:S3655")
public ResponseEntity getArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("artifactId") final Long artifactId) {
+
final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId);
- return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponse(module.getLocalArtifact(artifactId).get()),
- HttpStatus.OK);
+ return ResponseEntity.ok(toResponse(module.getLocalArtifact(artifactId).get()));
}
@Override
@ResponseBody
public ResponseEntity deleteArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("artifactId") final Long artifactId) {
- findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId);
+ findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId);
artifactManagement.deleteLocalArtifact(artifactId);
- return new ResponseEntity<>(HttpStatus.OK);
-
+ return ResponseEntity.ok().build();
}
@Override
@@ -143,33 +154,34 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
}
final List rest = MgmtSoftwareModuleMapper.toResponse(findModulesAll.getContent());
- return new ResponseEntity<>(new PagedList<>(rest, countModulesAll), HttpStatus.OK);
+ return ResponseEntity.ok(new PagedList<>(rest, countModulesAll));
}
@Override
public ResponseEntity getSoftwareModule(
@PathVariable("softwareModuleId") final Long softwareModuleId) {
- final SoftwareModule findBaseSoftareModule = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
- return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponse(findBaseSoftareModule), HttpStatus.OK);
+ final SoftwareModule findBaseSoftareModule = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
+ return ResponseEntity.ok(toResponse(findBaseSoftareModule));
}
@Override
public ResponseEntity> createSoftwareModules(
@RequestBody final List softwareModules) {
+
LOG.debug("creating {} softwareModules", softwareModules.size());
- final Iterable createdSoftwareModules = softwareManagement.createSoftwareModule(
+ final Collection createdSoftwareModules = softwareManagement.createSoftwareModule(
MgmtSoftwareModuleMapper.smFromRequest(entityFactory, softwareModules, softwareManagement));
LOG.debug("{} softwareModules created, return status {}", softwareModules.size(), HttpStatus.CREATED);
- return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponseSoftwareModules(createdSoftwareModules),
- HttpStatus.CREATED);
+ return ResponseEntity.status(CREATED).body(toResponse(createdSoftwareModules));
}
@Override
public ResponseEntity updateSoftwareModule(
@PathVariable("softwareModuleId") final Long softwareModuleId,
@RequestBody final MgmtSoftwareModuleRequestBodyPut restSoftwareModule) {
+
final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
// only description and vendor can be modified
@@ -181,16 +193,16 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
}
final SoftwareModule updateSoftwareModule = softwareManagement.updateSoftwareModule(module);
- return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponse(updateSoftwareModule), HttpStatus.OK);
+ return ResponseEntity.ok(toResponse(updateSoftwareModule));
}
@Override
public ResponseEntity deleteSoftwareModule(@PathVariable("softwareModuleId") final Long softwareModuleId) {
- final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
+ final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
softwareManagement.deleteSoftwareModule(module);
- return new ResponseEntity<>(HttpStatus.OK);
+ return ResponseEntity.ok().build();
}
@Override
@@ -218,34 +230,38 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
metaDataPage = softwareManagement.findSoftwareModuleMetadataBySoftwareModuleId(softwareModuleId, pageable);
}
- return new ResponseEntity<>(
- new PagedList<>(MgmtSoftwareModuleMapper.toResponseSwMetadata(metaDataPage.getContent()),
- metaDataPage.getTotalElements()),
- HttpStatus.OK);
+ return ResponseEntity
+ .ok(new PagedList<>(toResponseSwMetadata(metaDataPage.getContent()), metaDataPage.getTotalElements()));
}
@Override
public ResponseEntity getMetadataValue(@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("metadataKey") final String metadataKey) {
+
final SoftwareModule sw = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
final SoftwareModuleMetadata findOne = softwareManagement.findSoftwareModuleMetadata(sw, metadataKey);
- return ResponseEntity. ok(MgmtSoftwareModuleMapper.toResponseSwMetadata(findOne));
+
+ return ResponseEntity.ok(toResponseSwMetadata(findOne));
}
@Override
public ResponseEntity updateMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadata metadata) {
+
final SoftwareModule sw = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
final SoftwareModuleMetadata updated = softwareManagement.updateSoftwareModuleMetadata(
entityFactory.generateSoftwareModuleMetadata(sw, metadataKey, metadata.getValue()));
- return ResponseEntity.ok(MgmtSoftwareModuleMapper.toResponseSwMetadata(updated));
+
+ return ResponseEntity.ok(toResponseSwMetadata(updated));
}
@Override
public ResponseEntity deleteMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("metadataKey") final String metadataKey) {
+
final SoftwareModule sw = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
softwareManagement.deleteSoftwareModuleMetadata(sw, metadataKey);
+
return ResponseEntity.ok().build();
}
@@ -253,24 +269,25 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
public ResponseEntity> createMetadata(
@PathVariable("softwareModuleId") final Long softwareModuleId,
@RequestBody final List metadataRest) {
- final SoftwareModule sw = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
+ final SoftwareModule sw = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
final List created = softwareManagement.createSoftwareModuleMetadata(
MgmtSoftwareModuleMapper.fromRequestSwMetadata(entityFactory, sw, metadataRest));
- return new ResponseEntity<>(MgmtSoftwareModuleMapper.toResponseSwMetadata(created), HttpStatus.CREATED);
-
+ return ResponseEntity.status(CREATED).body(toResponseSwMetadata(created));
}
private SoftwareModule findSoftwareModuleWithExceptionIfNotFound(final Long softwareModuleId,
final Long artifactId) {
+
final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId);
if (module == null) {
throw new EntityNotFoundException("SoftwareModule with Id {" + softwareModuleId + "} does not exist");
- } else if (artifactId != null && !module.getLocalArtifact(artifactId).isPresent()) {
+ }
+ if (artifactId != null && !module.getLocalArtifact(artifactId).isPresent()) {
throw new EntityNotFoundException("Artifact with Id {" + artifactId + "} does not exist");
}
+
return module;
}
-
}
diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeMapper.java
index 565af7eb8..e14ed27fa 100644
--- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeMapper.java
+++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeMapper.java
@@ -11,9 +11,10 @@ package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
-import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType;
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost;
@@ -25,9 +26,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
* A mapper which maps repository model to RESTful model representation and
* back.
*
- *
- *
- *
*/
final class MgmtSoftwareModuleTypeMapper {
@@ -37,13 +35,12 @@ final class MgmtSoftwareModuleTypeMapper {
}
static List smFromRequest(final EntityFactory entityFactory,
- final Iterable smTypesRest) {
- final List mappedList = new ArrayList<>();
-
- for (final MgmtSoftwareModuleTypeRequestBodyPost smRest : smTypesRest) {
- mappedList.add(fromRequest(entityFactory, smRest));
+ final Collection smTypesRest) {
+ if (smTypesRest == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return smTypesRest.stream().map(smRest -> fromRequest(entityFactory, smRest)).collect(Collectors.toList());
}
static SoftwareModuleType fromRequest(final EntityFactory entityFactory,
@@ -57,20 +54,12 @@ final class MgmtSoftwareModuleTypeMapper {
return result;
}
- static List toTypesResponse(final List types) {
- final List response = new ArrayList<>();
- for (final SoftwareModuleType softwareModule : types) {
- response.add(toResponse(softwareModule));
+ static List toTypesResponse(final Collection types) {
+ if (types == null) {
+ return Collections.emptyList();
}
- return response;
- }
- static List toListResponse(final Collection types) {
- final List response = new ArrayList<>();
- for (final SoftwareModuleType softwareModule : types) {
- response.add(toResponse(softwareModule));
- }
- return response;
+ return types.stream().map(MgmtSoftwareModuleTypeMapper::toResponse).collect(Collectors.toList());
}
static MgmtSoftwareModuleType toResponse(final SoftwareModuleType type) {
diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResource.java
index 353cf16e5..762dd7c1c 100644
--- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResource.java
+++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResource.java
@@ -72,7 +72,7 @@ public class MgmtSoftwareModuleTypeResource implements MgmtSoftwareModuleTypeRes
}
final List rest = MgmtSoftwareModuleTypeMapper
- .toListResponse(findModuleTypessAll.getContent());
+ .toTypesResponse(findModuleTypessAll.getContent());
return new ResponseEntity<>(new PagedList<>(rest, countModulesAll), HttpStatus.OK);
}
diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetMapper.java
index a889edc35..014d0e9e3 100644
--- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetMapper.java
+++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetMapper.java
@@ -13,9 +13,11 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
import java.net.URI;
import java.time.ZoneId;
-import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.stream.Collectors;
import org.eclipse.hawkbit.mgmt.json.model.MgmtPollStatus;
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
@@ -92,17 +94,17 @@ public final class MgmtTargetMapper {
* the targets
* @return the response
*/
- public static List toResponseWithLinksAndPollStatus(final Iterable targets) {
- final List mappedList = new ArrayList<>();
- if (targets != null) {
- for (final Target target : targets) {
- final MgmtTarget response = toResponse(target);
- addPollStatus(target, response);
- addTargetLinks(response);
- mappedList.add(response);
- }
+ public static List toResponseWithLinksAndPollStatus(final Collection targets) {
+ if (targets == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return targets.stream().map(target -> {
+ final MgmtTarget response = toResponse(target);
+ addPollStatus(target, response);
+ addTargetLinks(response);
+ return response;
+ }).collect(Collectors.toList());
}
/**
@@ -112,15 +114,12 @@ public final class MgmtTargetMapper {
* list of targets
* @return the response
*/
- public static List toResponse(final Iterable targets) {
- final List mappedList = new ArrayList<>();
- if (targets != null) {
- for (final Target target : targets) {
- final MgmtTarget response = toResponse(target);
- mappedList.add(response);
- }
+ public static List toResponse(final Collection targets) {
+ if (targets == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return targets.stream().map(MgmtTargetMapper::toResponse).collect(Collectors.toList());
}
/**
@@ -173,12 +172,13 @@ public final class MgmtTargetMapper {
}
static List fromRequest(final EntityFactory entityFactory,
- final Iterable targetsRest) {
- final List mappedList = new ArrayList<>();
- for (final MgmtTargetRequestBody targetRest : targetsRest) {
- mappedList.add(fromRequest(entityFactory, targetRest));
+ final Collection targetsRest) {
+ if (targetsRest == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return targetsRest.stream().map(targetRest -> fromRequest(entityFactory, targetRest))
+ .collect(Collectors.toList());
}
static Target fromRequest(final EntityFactory entityFactory, final MgmtTargetRequestBody targetRest) {
@@ -190,17 +190,12 @@ public final class MgmtTargetMapper {
return target;
}
- static List toActionStatusRestResponse(final List actionStatus) {
- final List mappedList = new ArrayList<>();
-
- if (actionStatus != null) {
- for (final ActionStatus status : actionStatus) {
- final MgmtActionStatus response = toResponse(status);
- mappedList.add(response);
- }
+ static List toActionStatusRestResponse(final Collection actionStatus) {
+ if (actionStatus == null) {
+ return Collections.emptyList();
}
- return mappedList;
+ return actionStatus.stream().map(MgmtTargetMapper::toResponse).collect(Collectors.toList());
}
static MgmtAction toResponse(final String targetId, final Action action, final boolean isActive) {
@@ -222,14 +217,13 @@ public final class MgmtTargetMapper {
return result;
}
- static List toResponse(final String targetId, final List actions) {
- final List mappedList = new ArrayList<>();
-
- for (final Action action : actions) {
- final MgmtAction response = toResponse(targetId, action, action.isActive());
- mappedList.add(response);
+ static List toResponse(final String targetId, final Collection actions) {
+ if (actions == null) {
+ return Collections.emptyList();
}
- return mappedList;
+
+ return actions.stream().map(action -> toResponse(targetId, action, action.isActive()))
+ .collect(Collectors.toList());
}
private static String getNameOfActionStatusType(final Action.Status type) {
diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java
index 5ddb74314..d0d72be40 100644
--- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java
+++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
+import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -108,7 +109,7 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
@Override
public ResponseEntity> createTargets(@RequestBody final List targets) {
LOG.debug("creating {} targets", targets.size());
- final Iterable createdTargets = this.targetManagement
+ final Collection createdTargets = this.targetManagement
.createTargets(MgmtTargetMapper.fromRequest(entityFactory, targets));
LOG.debug("{} targets created, return status {}", targets.size(), HttpStatus.CREATED);
return new ResponseEntity<>(MgmtTargetMapper.toResponse(createdTargets), HttpStatus.CREATED);
diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResourceTest.java
index 9d5b0d002..0dd90b35f 100644
--- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResourceTest.java
+++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResourceTest.java
@@ -494,9 +494,6 @@ public class MgmtDistributionSetTypeResourceTest extends AbstractRestIntegration
final SoftwareModuleType testSmType = softwareManagement.createSoftwareModuleType(
entityFactory.generateSoftwareModuleType("test123", "TestName123", "Desc123", 5));
- final List types = new ArrayList<>();
- types.add(testType);
-
// DST does not exist
mvc.perform(get("/rest/v1/distributionsettypes/12345678")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
@@ -554,9 +551,8 @@ public class MgmtDistributionSetTypeResourceTest extends AbstractRestIntegration
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
- final DistributionSetType missingName = entityFactory.generateDistributionSetType("test123", null, "Desc123");
- mvc.perform(post("/rest/v1/distributionsettypes")
- .content(JsonBuilder.distributionSetTypes(Lists.newArrayList(missingName)))
+ // Missing mandatory field name
+ mvc.perform(post("/rest/v1/distributionsettypes").content("[{\"description\":\"Desc123\",\"key\":\"test123\"}]")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java
index f5c79fb6c..4f3e12b16 100644
--- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java
+++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java
@@ -438,8 +438,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
SoftwareModule sm = entityFactory.generateSoftwareModule(osType, "name 1", "version 1", null, null);
sm = softwareManagement.createSoftwareModule(sm);
- final List modules = new ArrayList<>();
- modules.add(sm);
+ final List modules = Lists.newArrayList(sm);
// SM does not exist
mvc.perform(get("/rest/v1/softwaremodules/12345678")).andDo(MockMvcResultPrinter.print())
@@ -457,11 +456,10 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
- final SoftwareModule missingName = entityFactory.generateSoftwareModule(osType, null, "version 1", null, null);
- mvc.perform(
- post("/rest/v1/softwaremodules").content(JsonBuilder.softwareModules(Lists.newArrayList(missingName)))
- .contentType(MediaType.APPLICATION_JSON))
- .andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
+ mvc.perform(post("/rest/v1/softwaremodules")
+ .content("[{\"description\":\"Desc123\",\"key\":\"test123\", \"type\":\"os\"}]")
+ .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
+ .andExpect(status().isBadRequest());
final SoftwareModule toLongName = entityFactory.generateSoftwareModule(osType,
RandomStringUtils.randomAscii(80), "version 1", null, null);
diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResourceTest.java
index 8c60815e3..8150eba54 100644
--- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResourceTest.java
+++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResourceTest.java
@@ -318,8 +318,7 @@ public class MgmtSoftwareModuleTypeResourceTest extends AbstractRestIntegrationT
final SoftwareModuleType testType = softwareManagement.createSoftwareModuleType(
entityFactory.generateSoftwareModuleType("test123", "TestName123", "Desc123", 5));
- final List types = new ArrayList<>();
- types.add(testType);
+ final List types = Lists.newArrayList(testType);
// SM does not exist
mvc.perform(get("/rest/v1/softwaremoduletypes/12345678")).andDo(MockMvcResultPrinter.print())
@@ -337,9 +336,9 @@ public class MgmtSoftwareModuleTypeResourceTest extends AbstractRestIntegrationT
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
- final SoftwareModuleType missingName = entityFactory.generateSoftwareModuleType("test123", null, "Desc123", 5);
mvc.perform(post("/rest/v1/softwaremoduletypes")
- .content(JsonBuilder.softwareModuleTypes(Lists.newArrayList(missingName)))
+ .content(
+ "[{\"description\":\"Desc123\",\"id\":9223372036854775807,\"key\":\"test123\",\"maxAssignments\":5}]")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
diff --git a/hawkbit-mgmt-resource/src/test/resources/logback-spring.xml b/hawkbit-mgmt-resource/src/test/resources/logback-spring.xml
index 6dd6c94e0..39f7e6bbf 100644
--- a/hawkbit-mgmt-resource/src/test/resources/logback-spring.xml
+++ b/hawkbit-mgmt-resource/src/test/resources/logback-spring.xml
@@ -23,7 +23,7 @@
-
+
diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java
index 167b6019f..b78d1500d 100644
--- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java
+++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java
@@ -208,15 +208,16 @@ public interface ArtifactManagement {
void deleteLocalArtifact(@NotNull Long id);
/**
- * Searches for {@link Artifact} with given {@link Identifiable}.
+ * Searches for {@link LocalArtifact} with given {@link Identifiable}.
*
* @param id
* to search for
- * @return found {@link Artifact} or null is it could not be
- * found.
+ * @return found {@link LocalArtifact} or null is it could not
+ * be found.
*/
- @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
- Artifact findArtifact(@NotNull Long id);
+ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
+ + SpringEvalExpressions.IS_CONTROLLER)
+ LocalArtifact findLocalArtifact(@NotNull Long id);
/**
* Find by artifact by software module id and filename.
diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java
index f93b42e48..58d26439d 100644
--- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java
+++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java
@@ -183,22 +183,6 @@ public interface ControllerManagement {
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
String getPollingTime();
- /**
- * An direct access to the security token of an
- * {@link Target#getSecurityToken()} without authorization. This is
- * necessary to be able to access the security-token without any
- * security-context information because the security-token is used for
- * authentication.
- *
- * @param controllerId
- * the ID of the controller to retrieve the security token for
- * @return the security context of the target, in case no target exists for
- * the given controllerId {@code null} is returned
- */
- @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER + SpringEvalExpressions.HAS_AUTH_OR
- + SpringEvalExpressions.HAS_AUTH_READ_TARGET_SEC_TOKEN)
- String getSecurityTokenByControllerId(@NotEmpty String controllerId);
-
/**
* Checks if a given target has currently or has even been assigned to the
* given artifact through the action history list. This can e.g. indicate if
@@ -218,6 +202,25 @@ public interface ControllerManagement {
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
boolean hasTargetArtifactAssigned(@NotNull String controllerId, @NotNull LocalArtifact localArtifact);
+ /**
+ * Checks if a given target has currently or has even been assigned to the
+ * given artifact through the action history list. This can e.g. indicate if
+ * a target is allowed to download a given artifact because it has currently
+ * assigned or had ever been assigned to the target and so it's visible to a
+ * specific target e.g. for downloading.
+ *
+ * @param targetId
+ * the ID of the target to check
+ * @param localArtifact
+ * the artifact to verify if the given target had even been
+ * assigned to
+ * @return {@code true} if the given target has currently or had ever a
+ * relation to the given artifact through the action history,
+ * otherwise {@code false}
+ */
+ @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
+ boolean hasTargetArtifactAssigned(@NotNull Long targetId, @NotNull LocalArtifact localArtifact);
+
/**
* Registers retrieved status for given {@link Target} and {@link Action} if
* it does not exist yet.
@@ -300,4 +303,32 @@ public interface ControllerManagement {
TargetInfo updateTargetStatus(@NotNull TargetInfo targetInfo, TargetUpdateStatus status, Long lastTargetQuery,
URI address);
+ /**
+ * Finds {@link Target} based on given controller ID returns found Target
+ * without details, i.e. NO {@link Target#getTags()} and
+ * {@link Target#getActions()} possible.
+ *
+ * @param controllerId
+ * to look for.
+ * @return {@link Target} or {@code null} if it does not exist
+ * @see Target#getControllerId()
+ */
+ @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER + SpringEvalExpressions.HAS_AUTH_OR
+ + SpringEvalExpressions.IS_SYSTEM_CODE)
+ Target findByControllerId(@NotEmpty final String controllerId);
+
+ /**
+ * Finds {@link Target} based on given ID returns found Target without
+ * details, i.e. NO {@link Target#getTags()} and {@link Target#getActions()}
+ * possible.
+ *
+ * @param targetId
+ * to look for.
+ * @return {@link Target} or {@code null} if it does not exist
+ * @see Target#getId()
+ */
+ @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER + SpringEvalExpressions.HAS_AUTH_OR
+ + SpringEvalExpressions.IS_SYSTEM_CODE)
+ Target findByTargetId(final long targetId);
+
}
diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetAssignmentResult.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetAssignmentResult.java
index 704bb38e9..171808cb0 100644
--- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetAssignmentResult.java
+++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetAssignmentResult.java
@@ -57,7 +57,11 @@ public class DistributionSetAssignmentResult extends AssignmentResult {
* @return the actionIds
*/
public List getActions() {
- return actions;
+ if (actions == null) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(actions);
}
@Override
diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java
index d8a6f54fe..1de51fad9 100644
--- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java
+++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java
@@ -205,8 +205,10 @@ public interface DistributionSetManagement {
/**
* deletes a distribution set meta data entry.
*
- * @param id
- * the ID of the distribution set meta data to delete
+ * @param distributionSet
+ * where meta data has to be deleted
+ * @param key
+ * of the meta data element
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
void deleteDistributionSetMetadata(@NotNull final DistributionSet distributionSet, @NotNull final String key);
@@ -429,7 +431,7 @@ public interface DistributionSetManagement {
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
- DistributionSetType findDistributionSetTypeByKey(@NotNull String key);
+ DistributionSetType findDistributionSetTypeByKey(@NotEmpty String key);
/**
* @param name
@@ -469,15 +471,16 @@ public interface DistributionSetManagement {
/**
* finds a single distribution set meta data by its id.
*
- * @param id
- * the id of the distribution set meta data containing the meta
- * data key and the ID of the distribution set
+ * @param distributionSet
+ * where meta data has to rind
+ * @param key
+ * of the meta data element
* @return the found DistributionSetMetadata or {@code null} if not exits
* @throws EntityNotFoundException
* in case the meta data does not exists for the given key
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
- DistributionSetMetadata findOne(@NotNull DistributionSet distributionSet, @NotNull String key);
+ DistributionSetMetadata findOne(@NotNull DistributionSet distributionSet, @NotEmpty String key);
/**
* Checks if a {@link DistributionSet} is currently in use by a target in
diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/EntityFactory.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/EntityFactory.java
index 87919729e..925351807 100644
--- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/EntityFactory.java
+++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/EntityFactory.java
@@ -11,6 +11,8 @@ package org.eclipse.hawkbit.repository;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
+import javax.validation.constraints.NotNull;
+
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
@@ -64,7 +66,7 @@ public interface EntityFactory {
*
* @return {@link ActionStatus} object
*/
- ActionStatus generateActionStatus(Action action, Status status, Long occurredAt);
+ ActionStatus generateActionStatus(@NotNull Action action, @NotNull Status status, Long occurredAt);
/**
* Generates an {@link ActionStatus} object without persisting it.
@@ -81,7 +83,7 @@ public interface EntityFactory {
*
* @return {@link ActionStatus} object
*/
- ActionStatus generateActionStatus(Action action, final Status status, Long occurredAt,
+ ActionStatus generateActionStatus(@NotNull Action action, @NotNull Status status, Long occurredAt,
final Collection messages);
/**
@@ -99,7 +101,8 @@ public interface EntityFactory {
*
* @return {@link ActionStatus} object
*/
- ActionStatus generateActionStatus(Action action, Status status, Long occurredAt, final String message);
+ ActionStatus generateActionStatus(@NotNull Action action, @NotNull Status status, Long occurredAt,
+ final String message);
/**
* Generates an empty {@link DistributionSet} without persisting it.
@@ -124,8 +127,8 @@ public interface EntityFactory {
*
* @return {@link DistributionSet} object
*/
- DistributionSet generateDistributionSet(String name, String version, String description, DistributionSetType type,
- Collection moduleList);
+ DistributionSet generateDistributionSet(@NotNull String name, @NotNull String version, String description,
+ @NotNull DistributionSetType type, Collection moduleList);
/**
* Generates an empty {@link DistributionSetMetadata} element without
@@ -148,7 +151,8 @@ public interface EntityFactory {
*
* @return {@link DistributionSetMetadata} object
*/
- DistributionSetMetadata generateDistributionSetMetadata(DistributionSet distributionSet, String key, String value);
+ DistributionSetMetadata generateDistributionSetMetadata(@NotNull DistributionSet distributionSet,
+ @NotNull String key, String value);
/**
* Generates an empty {@link DistributionSetTag} without persisting it.
@@ -164,7 +168,7 @@ public interface EntityFactory {
* of the tag
* @return {@link DistributionSetTag} object
*/
- DistributionSetTag generateDistributionSetTag(String name);
+ DistributionSetTag generateDistributionSetTag(@NotNull String name);
/**
* Generates a {@link DistributionSetTag} without persisting it.
@@ -177,7 +181,7 @@ public interface EntityFactory {
* of the tag
* @return {@link DistributionSetTag} object
*/
- DistributionSetTag generateDistributionSetTag(String name, String description, String colour);
+ DistributionSetTag generateDistributionSetTag(@NotNull String name, String description, String colour);
/**
* Generates an empty {@link DistributionSetType} without persisting it.
@@ -198,7 +202,7 @@ public interface EntityFactory {
*
* @return {@link DistributionSetType} object
*/
- DistributionSetType generateDistributionSetType(String key, String name, String description);
+ DistributionSetType generateDistributionSetType(@NotNull String key, @NotNull String name, String description);
/**
* Generates an empty {@link Rollout} without persisting it.
@@ -237,8 +241,8 @@ public interface EntityFactory {
*
* @return {@link SoftwareModule} object
*/
- SoftwareModule generateSoftwareModule(SoftwareModuleType type, String name, String version, String description,
- String vendor);
+ SoftwareModule generateSoftwareModule(@NotNull SoftwareModuleType type, @NotNull String name,
+ @NotNull String version, String description, String vendor);
/**
* Generates an empty {@link SoftwareModuleMetadata} pair without persisting
@@ -260,7 +264,8 @@ public interface EntityFactory {
*
* @return {@link SoftwareModuleMetadata} object
*/
- SoftwareModuleMetadata generateSoftwareModuleMetadata(SoftwareModule softwareModule, String key, String value);
+ SoftwareModuleMetadata generateSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotNull String key,
+ String value);
/**
* Generates an empty {@link SoftwareModuleType} without persisting it.
@@ -283,7 +288,8 @@ public interface EntityFactory {
*
* @return {@link SoftwareModuleType} object
*/
- SoftwareModuleType generateSoftwareModuleType(String key, String name, String description, int maxAssignments);
+ SoftwareModuleType generateSoftwareModuleType(@NotNull String key, @NotNull String name, String description,
+ int maxAssignments);
/**
* Generates an empty {@link Target} without persisting it.
@@ -307,7 +313,7 @@ public interface EntityFactory {
*
* @return {@link Target} object
*/
- Target generateTarget(@NotEmpty String controllerID, @NotEmpty String securityToken);
+ Target generateTarget(@NotEmpty String controllerID, String securityToken);
/**
* Generates an empty {@link TargetFilterQuery} without persisting it.
@@ -330,7 +336,7 @@ public interface EntityFactory {
* of the tag
* @return {@link TargetTag} object
*/
- TargetTag generateTargetTag(String name);
+ TargetTag generateTargetTag(@NotNull String name);
/**
* Generates a {@link TargetTag} without persisting it.
@@ -343,7 +349,7 @@ public interface EntityFactory {
* of the tag
* @return {@link TargetTag} object
*/
- TargetTag generateTargetTag(String name, String description, String colour);
+ TargetTag generateTargetTag(@NotNull String name, String description, String colour);
/**
* Generates an empty {@link LocalArtifact} without persisting it.
diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java
index dfe05100e..2746686a7 100644
--- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java
+++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java
@@ -155,11 +155,13 @@ public interface SoftwareManagement {
/**
* deletes a software module meta data entry.
*
- * @param id
- * the ID of the software module meta data to delete
+ * @param softwareModule
+ * where meta data has to be deleted
+ * @param key
+ * of the metda data element
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
- void deleteSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotNull String key);
+ void deleteSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotEmpty String key);
/**
* Deletes {@link SoftwareModule}s which is any if the given ids.
@@ -251,9 +253,10 @@ public interface SoftwareManagement {
/**
* finds a single software module meta data by its id.
*
- * @param id
- * the id of the software module meta data containing the meta
- * data key and the ID of the software module
+ * @param softwareModule
+ * where meta data has to be found
+ * @param key
+ * of the meta data element
* @return the found SoftwareModuleMetadata or {@code null} if not exits
* @throws EntityNotFoundException
* in case the meta data does not exists for the given key
@@ -280,8 +283,8 @@ public interface SoftwareManagement {
*
* @param softwareModuleId
* the software module id to retrieve the meta data from
- * @param spec
- * the specification to filter the result
+ * @param rsqlParam
+ * filter definition in RSQL syntax
* @param pageable
* the page request to page the result
* @return a paged result of all meta data entries for a given software
@@ -346,8 +349,8 @@ public interface SoftwareManagement {
/**
* Retrieves all {@link SoftwareModule}s with a given specification.
*
- * @param spec
- * the specification to filter the software modules
+ * @param rsqlParam
+ * filter definition in RSQL syntax
* @param pageable
* pagination parameter
* @return the found {@link SoftwareModule}s
@@ -392,7 +395,7 @@ public interface SoftwareManagement {
* {@link SoftwareModuleType#getKey()}
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
- SoftwareModuleType findSoftwareModuleTypeByKey(@NotNull String key);
+ SoftwareModuleType findSoftwareModuleTypeByKey(@NotEmpty String key);
/**
*
@@ -415,8 +418,8 @@ public interface SoftwareManagement {
/**
* Retrieves all {@link SoftwareModuleType}s with a given specification.
*
- * @param spec
- * the specification to filter the software modules types
+ * @param rsqlParam
+ * filter definition in RSQL syntax
* @param pageable
* pagination parameter
* @return the found {@link SoftwareModuleType}s
diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java
index cd414b09a..131f63107 100644
--- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java
+++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java
@@ -63,7 +63,8 @@ public interface SystemManagement {
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
- + SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
+ + SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION + SpringEvalExpressions.HAS_AUTH_OR
+ + SpringEvalExpressions.IS_CONTROLLER)
TenantMetaData getTenantMetadata();
/**
@@ -93,4 +94,14 @@ public interface SystemManagement {
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
TenantMetaData updateTenantMetadata(@NotNull TenantMetaData metaData);
+ /**
+ * Returns {@link TenantMetaData} of given tenant ID.
+ *
+ * @param tenantId
+ * to retrieve data for
+ * @return {@link TenantMetaData} of given tenant
+ */
+ @PreAuthorize(SpringEvalExpressions.IS_SYSTEM_CODE)
+ TenantMetaData getTenantMetadata(@NotNull Long tenantId);
+
}
diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupCreatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupCreatedEvent.java
index 41f08c91d..47fb6b39e 100644
--- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupCreatedEvent.java
+++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/RolloutGroupCreatedEvent.java
@@ -34,6 +34,8 @@ public class RolloutGroupCreatedEvent extends AbstractDistributedEvent {
* the revision of the event
* @param rolloutId
* the ID of the rollout the group has been created
+ * @param rolloutGroupId
+ * identifier of this group
* @param totalRolloutGroup
* the total number of rollout groups for this rollout
* @param createdRolloutGroup
diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetAssignDistributionSetEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetAssignDistributionSetEvent.java
index 586a4b9d2..e87d49b57 100644
--- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetAssignDistributionSetEvent.java
+++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetAssignDistributionSetEvent.java
@@ -8,11 +8,11 @@
*/
package org.eclipse.hawkbit.repository.eventbus.event;
-import java.net.URI;
import java.util.Collection;
import org.eclipse.hawkbit.eventbus.event.DefaultEvent;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
+import org.eclipse.hawkbit.repository.model.Target;
/**
* Event that gets sent when a distribution set gets assigned to a target.
@@ -21,10 +21,8 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
public class TargetAssignDistributionSetEvent extends DefaultEvent {
private final Collection softwareModules;
- private final String controllerId;
+ private final Target target;
private final Long actionId;
- private final URI targetAdress;
- private final String targetToken;
/**
* Creates a new {@link TargetAssignDistributionSetEvent}.
@@ -33,26 +31,19 @@ public class TargetAssignDistributionSetEvent extends DefaultEvent {
* the revision of the event
* @param tenant
* the tenant of the event
- * @param controllerId
- * the ID of the controller
+ * @param target
+ * the assigned {@link Target}
* @param actionId
* the action id of the assignment
* @param softwareModules
* the software modules which have been assigned to the target
- * @param targetAdress
- * the targetAdress of the target
- * @param targetToken
- * the authentication token of the target
*/
- public TargetAssignDistributionSetEvent(final long revision, final String tenant, final String controllerId,
- final Long actionId, final Collection softwareModules, final URI targetAdress,
- final String targetToken) {
+ public TargetAssignDistributionSetEvent(final long revision, final String tenant, final Target target,
+ final Long actionId, final Collection